题目描述:
N个点M条边的无向图,询问保留图中编号在[l,r]的边的时候图中的联通块个数。
输入格式:
第一行四个整数N、M、K、type,代表点数、边数、询问数以及询问是否加密。 接下来M行,代表图中的每条边。 接下来K行,每行两个整数L、R代表一组询问。对于type=0的测试点,读入的L和R即为询问的L、R;对于type=1的测试点,每组询问的L、R应为L xor lastans和R xor lastans。
输出格式:
K行每行一个整数代表该组询问的联通块个数。
题解:
连通问题首先考虑LCT。
考虑连通块个数的计算方法。
连通块个数=点数-去掉重边后的边数。
逐个枚举边,如果这条边连接的两个点没有连通,连接这条边;反之,把两点间最早的边弹出,连接这条边,并记录弹出边的编号。
每次查询区间时,如果这条边弹出的边在区间内,那么这条边是无效的。
所以问题转化为求区间内小于某个数的数的个数,可以主席树维护。
时间复杂度$O(nlog_n)$
Code:
1 #include<iostream> 2 #include<cstdio> 3 using namespace std; 4 const int N=400010; 5 const int inf=1e9+10; 6 int n,m,k,ty,cnt,top; 7 int a[N<<1],st[N<<1],ch[N<<1][2],f[N<<1],rev[N<<1],mi[N<<1]; 8 int u[N],v[N],rt[N],b[N],an[N]; 9 struct seg{ 10 int lc,rc,w; 11 }t[N<<5]; 12 int read() 13 { 14 int s=0;char c=getchar(); 15 while(c<'0'||c>'9') c=getchar(); 16 while(c>='0'&&c<='9'){ 17 s=(s<<3)+(s<<1)+c-'0'; 18 c=getchar(); 19 } 20 return s; 21 } 22 int get(int x) 23 { 24 return ch[f[x]][1]==x; 25 } 26 bool isroot(int x) 27 { 28 return ch[f[x]][0]!=x&&ch[f[x]][1]!=x; 29 } 30 void pushup(int x) 31 { 32 mi[x]=a[x]; 33 if(ch[x][0]) mi[x]=min(mi[x],mi[ch[x][0]]); 34 if(ch[x][1]) mi[x]=min(mi[x],mi[ch[x][1]]); 35 } 36 void pushdown(int x) 37 { 38 if(rev[x]){ 39 swap(ch[x][0],ch[x][1]); 40 if(ch[x][0]) rev[ch[x][0]]^=1; 41 if(ch[x][1]) rev[ch[x][1]]^=1; 42 rev[x]=0; 43 } 44 } 45 void rotate(int x) 46 { 47 int y=f[x],z=f[y],k=get(x); 48 if(!isroot(y)){ 49 if(ch[z][0]==y) ch[z][0]=x; 50 else ch[z][1]=x; 51 } 52 f[x]=z;f[y]=x;f[ch[x][k^1]]=y; 53 ch[y][k]=ch[x][k^1];ch[x][k^1]=y; 54 pushup(y);pushup(x); 55 } 56 void splay(int x) 57 { 58 top=0;st[++top]=x; 59 for(int i=x;!isroot(i);i=f[i]) st[++top]=f[i]; 60 for(int i=top;i>=1;i--) pushdown(st[i]); 61 while(!isroot(x)){ 62 int y=f[x]; 63 if(!isroot(y)){ 64 if(get(x)==get(y)) rotate(y); 65 else rotate(x); 66 } 67 rotate(x); 68 } 69 } 70 void access(int x) 71 { 72 for(int y=0;x;y=x,x=f[x]){ 73 splay(x);ch[x][1]=y;pushup(x); 74 } 75 } 76 void makeroot(int x) 77 { 78 access(x);splay(x); 79 rev[x]^=1; 80 } 81 void split(int x,int y) 82 { 83 makeroot(x); 84 access(y);splay(y); 85 } 86 void link(int x,int y) 87 { 88 makeroot(x); 89 f[x]=y; 90 } 91 void cut(int x,int y) 92 { 93 split(x,y); 94 f[x]=ch[y][0]=0; 95 } 96 int find(int x) 97 { 98 access(x);splay(x); 99 pushdown(x); 100 while(ch[x][0]){ 101 pushdown(ch[x][0]); 102 x=ch[x][0]; 103 } 104 splay(x); 105 return x; 106 } 107 void insert(int lk,int &rk,int l,int r,int x) 108 { 109 if(rk==0) rk=++cnt; 110 t[rk].w=t[lk].w+1; 111 if(l==r) return; 112 int mid=(l+r)>>1; 113 if(x<=mid){ 114 t[rk].rc=t[lk].rc; 115 insert(t[lk].lc,t[rk].lc,l,mid,x); 116 } 117 else{ 118 t[rk].lc=t[lk].lc; 119 insert(t[lk].rc,t[rk].rc,mid+1,r,x); 120 } 121 } 122 int que(int lk,int rk,int L,int R,int l,int r) 123 { 124 if(L>=l&&R<=r) return t[rk].w-t[lk].w; 125 int mid=(L+R)>>1; 126 if(r<=mid) return que(t[lk].lc,t[rk].lc,L,mid,l,r); 127 else if(l>mid) return que(t[lk].rc,t[rk].rc,mid+1,R,l,r); 128 else return que(t[lk].lc,t[rk].lc,L,mid,l,r)+que(t[lk].rc,t[rk].rc,mid+1,R,l,r); 129 } 130 int main() 131 { 132 n=read();m=read();k=read();ty=read(); 133 for(int i=1;i<=n;i++) a[i]=inf; 134 for(int i=1;i<=m;i++){ 135 u[i]=read();v[i]=read();a[i+n]=i; 136 if(u[i]!=v[i]){ 137 int x=find(u[i]),y=find(v[i]); 138 if(x==y){ 139 split(u[i],v[i]); 140 b[i]=mi[v[i]]; 141 cut(u[b[i]],b[i]+n); 142 cut(b[i]+n,v[b[i]]); 143 } 144 link(u[i],i+n); 145 link(i+n,v[i]); 146 insert(rt[i-1],rt[i],0,m,b[i]); 147 } 148 else rt[i]=rt[i-1]; 149 } 150 for(int i=1;i<=k;i++){ 151 int l=read(),r=read(); 152 if(ty){ 153 l^=an[i-1];r^=an[i-1]; 154 } 155 an[i]=n-que(rt[l-1],rt[r],0,m,0,l-1); 156 } 157 for(int i=1;i<=k;i++) printf("%d ",an[i]); 158 return 0; 159 }