bzoj 3514: Codechef MARCH14 GERALD07加强版

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

一开始看到这个题的时候第一眼想法就是暴力莫队+LCT,然而是强制在线QAQ。。。

然后就不会了,然后就颓了。。。根本想不到这题跟主席树有什么关系。。。

看了题解之后膝盖都给跪烂,Orz%%%

做法是这样的:

不断加边,如果产生了环,那么把环上编号最小的边给删掉,并且用ntr[i]记录该边把哪条边给删掉了。。。如果没删掉就是0;

对于每个l-r区间的询问查找这些边有多少边的ntr[i]<l(num),对于每个询问的答案为n-num;

这样为什么是对的呢???

对于一条边,如果ntr[i]>=l,那么他一定可以与l--r这个区间的边产生一个环。。。环的话对于连通块的数量是没有贡献的。

反之,如果一条边的ntr[i]<l,那么他肯定不可能与l--r这个区间中的边产生环,也就相当于这条边对于l--r这个区间是一条树边,而每一条树边的贡献相当于是减少一个连通块。。。

所以这样是有正确性的。。。

加边删边是可以用LCT实现的,注意使用把边当做点的技巧。。。

而查询区间中用小于l的边有多少个是可以用主席树实现的。。。

以下附代码:

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<algorithm>
  4 #include<cstring>
  5 using namespace std;
  6 const int N=400050;
  7 const int INF=2147483647;
  8 int gi()
  9 {
 10     int x=0;
 11     char ch=getchar();
 12     while(ch<'0'||ch>'9') ch=getchar();
 13     while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
 14     return x;
 15 }
 16 int c[N][2],fa[N],minm[N],st[N],rev[N],root[N*20],s[N*20],sz,ls[N*20],rs[N*20],w[N];
 17 int n,m,k,type,ntr[N*2],last;
 18 struct ac
 19 {
 20     int x,y,id;
 21 }e[N];
 22 bool isroot(int x){return c[fa[x]][0]!=x&&c[fa[x]][1]!=x;}
 23 void update(int x)
 24 {
 25     int l=c[x][0],r=c[x][1];
 26     minm[x]=x;
 27     if(w[minm[x]]>w[minm[l]]) minm[x]=minm[l];
 28     if(w[minm[x]]>w[minm[r]]) minm[x]=minm[r];
 29 }
 30 void pushdown(int x)
 31 {
 32     int l=c[x][0],r=c[x][1];
 33     if(rev[x])
 34     {
 35         rev[x]^=1;rev[l]^=1;rev[r]^=1;
 36         swap(c[x][0],c[x][1]);
 37     }
 38 }
 39 void rotate(int x)
 40 {
 41     int y=fa[x],z=fa[y],l,r;
 42     if(c[y][0]==x) l=0;else l=1;r=l^1;
 43     if(!isroot(y))
 44     {
 45         if(c[z][0]==y) c[z][0]=x;
 46         else c[z][1]=x;
 47     }
 48     fa[y]=x;fa[x]=z;fa[c[x][r]]=y;
 49     c[y][l]=c[x][r];c[x][r]=y;
 50     update(y);update(x);
 51 }
 52 void splay(int x)
 53 {
 54     int top=0;st[++top]=x;
 55     for(int i=x;!isroot(i);i=fa[i]) st[++top]=fa[i];
 56     for(int i=top;i;i--) pushdown(st[i]);
 57     while(!isroot(x))
 58     {
 59         int y=fa[x],z=fa[y];
 60         if(!isroot(y))
 61         {
 62             if(c[y][0]==x^c[z][0]==y) rotate(x);
 63             else rotate(y);
 64         }
 65         rotate(x);
 66     }
 67 }
 68 void access(int x)
 69 {
 70     int t=0;
 71     while(x)
 72     {
 73         splay(x);
 74         c[x][1]=t;
 75         t=x;update(x);x=fa[x];
 76     }
 77 }
 78 void rever(int x) {access(x),splay(x),rev[x]^=1;}
 79 void lnk(int x,int y) {rever(x);fa[x]=y;}
 80 void cut(int x,int y) {rever(x);access(y);splay(y);c[y][0]=fa[x]=0;}
 81 int query1(int x,int y) {rever(x);access(y);splay(y);return minm[y];}
 82 int find(int x)
 83 {
 84     access(x);splay(x);
 85     while(c[x][0])x=c[x][0];
 86     return x;
 87 }
 88 void insert(int l,int r,int x,int &y,int v)
 89 {
 90     y=++sz;s[y]=s[x]+1;
 91     ls[y]=ls[x];rs[y]=rs[x];
 92     if(l==r) return;
 93     int mid=(l+r)>>1;
 94     if(v<=mid) insert(l,mid,ls[x],ls[y],v);
 95     else insert(mid+1,r,rs[x],rs[y],v);
 96 }
 97 int query(int l,int r,int x,int y,int v)
 98 {
 99     if(l==r) return s[y]-s[x];
100     int mid=(l+r)>>1;
101     if(v<=mid) return query(l,mid,ls[x],ls[y],v);
102     else return s[ls[y]]-s[ls[x]]+query(mid+1,r,rs[x],rs[y],v);
103 }
104 void pre()
105 {
106     for(int i=1;i<=m;i++)
107     {
108         if(e[i].x==e[i].y) {ntr[i]=i;continue;}
109         if(find(e[i].x)!=find(e[i].y)) 
110         {
111             w[n+i]=n+i;minm[n+i]=n+i;
112             lnk(n+i,e[i].x);lnk(n+i,e[i].y);
113         }
114         else if(find(e[i].x)==find(e[i].y))
115         {
116             int mm=query1(e[i].x,e[i].y);ntr[i]=mm-n;
117             cut(e[mm-n].x,mm);cut(e[mm-n].y,mm);
118             w[n+i]=i+n;minm[n+i]=n+i;
119             lnk(e[i].x,n+i);lnk(e[i].y,n+i);
120         }
121     }
122     for(int i=1;i<=m;i++) insert(0,m,root[i-1],root[i],ntr[i]);
123 }
124 void work()
125 {
126     int l,r;
127     for(int i=1;i<=k;i++)
128     {
129         l=gi();r=gi();
130         if(type) l^=last,r^=last;
131         last=n-query(0,m,root[l-1],root[r],l-1);
132         printf("%d\n",last);
133     }
134 }
135 int main()
136 {
137   n=gi();m=gi();k=gi();type=gi();
138   for(int i=1;i<=m;i++) e[i].x=gi(),e[i].y=gi(),e[i].id=i;
139   w[0]=INF;
140   for(int i=1;i<=n;i++) w[i]=INF,minm[i]=i;
141   pre();
142   work();
143   return 0;
144 }

 

posted @ 2017-03-01 21:18  qt666  阅读(145)  评论(0编辑  收藏  举报