bzoj3514 Codechef MARCH14 GERALD07加强版 lct预处理+主席树

Codechef MARCH14 GERALD07加强版

Time Limit: 60 Sec  Memory Limit: 256 MB
Submit: 1951  Solved: 746
[Submit][Status][Discuss]

Description

N个点M条边的无向图,询问保留图中编号在[l,r]的边的时候图中的联通块个数。

Input

第一行四个整数N、M、K、type,代表点数、边数、询问数以及询问是否加密。
接下来M行,代表图中的每条边。
接下来K行,每行两个整数L、R代表一组询问。对于type=0的测试点,读入的L和R即为询问的L、R;对于type=1的测试点,每组询问的L、R应为L xor lastans和R xor lastans。

Output

 K行每行一个整数代表该组询问的联通块个数。

Sample Input

3 5 4 0
1 3
1 2
2 1
3 2
2 2
2 3
1 5
5 5
1 2

Sample Output

2
1
3
1

HINT

 

对于100%的数据,1≤N、M、K≤200,000。


2016.2.26提高时限至60s

 

Source

By zhonghaoxi

 

题解:

  首先把边依次加到图中,若当前这条边与图中的边形成了环,那么把这个环中最早加进来的边弹出去
  并将每条边把哪条边弹了出去记录下来:ntr[i] = j,特别地,要是没有弹出边,ntr[i] = 0;
  这个显然是可以用LCT来弄的对吧。
  然后对于每个询问,我们的答案就是对l~r中ntr小于l的边求和,并用n减去这个值
  正确性可以YY一下:
  如果一条边的ntr >= l,那么显然他可以与从l ~ r中的边形成环,那么它对答案没有贡献
  反之如果一条边的ntr < l那么它与从l ~ r中的边是不能形成环的,那么他对答案的贡献为-1
  对于查询从l ~ r中有多少边的ntr小于l。

  函数式线段树询问即可

  

  比如这个图,如果询问2-5那么,对于5这条边来说,是没意义的,因为5只能将

  2这条边的效果去掉,因为2最早,所以不能算,

  因此ans=4-3=1而不是4-4=0

  

  函数式线段树记录什么呢,就是rt[i]表示i为右端点,

  然后左端点的话就是维护前缀和的形式即可。

 

 

  1 #include<cstring>
  2 #include<cmath>
  3 #include<iostream>
  4 #include<algorithm>
  5 #include<cstdio>
  6 
  7 #define inf 1000000000
  8 #define ll long long 
  9 #define N 400005
 10 #define M 200005
 11 #define NUM 4000007
 12 using namespace std;
 13 inline int read()
 14 {
 15     int x=0,f=1;char ch=getchar();
 16     while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
 17     while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
 18     return x*f;
 19 }
 20 
 21 int n,m,q,ans,tot,sz,flag;
 22 int s[N],st[M],root[M];
 23 int c[N][2],fa[N],val[N],mn[N],sum[NUM],ls[NUM],rs[NUM],rev[N];
 24 struct Node
 25 {
 26     int u,v;
 27 }e[M];
 28 
 29 inline bool isroot(int x){return c[fa[x]][0]!=x&&c[fa[x]][1]!=x;}
 30 void update(int p)
 31 {
 32     int l=c[p][0],r=c[p][1];mn[p]=p;
 33     if(val[mn[l]]<val[mn[p]])mn[p]=mn[l];
 34     if(val[mn[r]]<val[mn[p]])mn[p]=mn[r];    
 35 }
 36 void pushdown(int x)
 37 {
 38     int l=c[x][0],r=c[x][1];
 39     if(rev[x])
 40     {
 41         rev[x]^=1;rev[l]^=1;rev[r]^=1;
 42         swap(c[x][0],c[x][1]);
 43     }
 44 }
 45 void rotate(int x)
 46 {
 47     int y=fa[x],z=fa[y],l,r;
 48     if(c[y][0]==x)l=0;else l=1;r=l^1;
 49     if(!isroot(y))
 50     {
 51         if(c[z][0]==y)c[z][0]=x;else c[z][1]=x;
 52     }
 53     fa[y]=x,fa[x]=z,fa[c[x][r]]=y;
 54     c[y][l]=c[x][r],c[x][r]=y;
 55     update(y),update(x);
 56 }
 57 void splay(int x)
 58 {
 59     int top=0;s[++top]=x;
 60     for(int i=x;!isroot(i);i=fa[i])s[++top]=fa[i];
 61     for(int i=top;i;i--)pushdown(s[i]);
 62     while(!isroot(x))
 63     {
 64         int y=fa[x],z=fa[y];
 65         if(!isroot(y))
 66         {
 67             if(c[y][0]==x^c[z][0]==y)rotate(x);
 68             else rotate(y);
 69         }
 70         rotate(x);
 71     }
 72     update(x);
 73 }
 74 void access(int x)
 75 {
 76     for(int t=0;x!=0;t=x,x=fa[x])
 77         splay(x),c[x][1]=t,update(x);
 78 }
 79 void makeroot(int x)
 80 {
 81     access(x);
 82     splay(x);
 83     rev[x]^=1;
 84 }
 85 void link(int x,int y)
 86 {
 87     makeroot(x);
 88     fa[x]=y;
 89 }
 90 void cut(int x,int y)
 91 {
 92     makeroot(x),access(y),splay(y);
 93     c[y][0]=fa[x]=0;
 94 }
 95 int find(int x)
 96 {
 97     access(x),splay(x);
 98     while(c[x][0])
 99         x=c[x][0];
100     return x;
101 }
102 int query(int x,int y)
103 {
104     makeroot(x);
105     access(y);
106     splay(y);
107     return mn[y];
108 }
109 void ins(int l,int r,int x,int &y,int val)
110 {
111     y=++sz,sum[y]=sum[x]+1;
112     if(l==r)return;
113     ls[y]=ls[x];rs[y]=rs[x];
114     int mid=(l+r)>>1;
115     if(val<=mid)ins(l,mid,ls[x],ls[y],val);
116     else ins(mid+1,r,rs[x],rs[y],val);
117 }
118 int query(int l,int r,int x,int y,int val)
119 {
120     if(r==val)return sum[y]-sum[x];
121     int mid=(l+r)>>1;
122     if(val<=mid)return query(l,mid,ls[x],ls[y],val);
123     else return sum[ls[y]]-sum[ls[x]]+query(mid+1,r,rs[x],rs[y],val);
124 }
125 void init()
126 {
127     tot=n;
128     for(int i=1;i<=m;i++)
129     {
130         int u=e[i].u,v=e[i].v;
131         if(u==v){st[i]=i;continue;}
132         if(find(u)==find(v))
133         {
134             int t=query(u,v),x=val[t];
135             st[i]=x;
136             cut(e[x].u,t);cut(e[x].v,t);
137         }
138         tot++,mn[tot]=tot,val[tot]=i;
139         link(u,tot),link(v,tot);
140     }
141     for(int i=1;i<=m;i++)
142         ins(0,m,root[i-1],root[i],st[i]);
143 }
144 int main()
145 {
146     n=read(),m=read(),q=read(),flag=read();
147     val[0]=inf;
148     for(int i=1;i<=n;i++) mn[i]=i,val[i]=inf;
149     for(int i=1;i<=m;i++) e[i].u=read(),e[i].v=read();
150     
151     init();
152     
153     for(int i=1;i<=q;i++)
154     {
155         int l=read(),r=read();
156         if(flag)l^=ans,r^=ans;
157         ans=n-query(0,m,root[l-1],root[r],l-1);
158         printf("%d\n",ans);
159     }
160 }

 

posted @ 2017-12-24 16:19  Kaiser-  阅读(181)  评论(0编辑  收藏  举报