来自FallDream的博客,未经允许,请勿转载,谢谢。
N个点M条边的无向图,询问保留图中编号在[l,r]的边的时候图中的联通块个数。 n,m<=200000 强制在线
如果我能知道每条边在什么时候有贡献,我就能算出答案,所以考虑找到最迟的和它冲突的边。
找的方法可以以编号为边权,用一个LCT维护最大生成树,每次如果冲突就找到最小的边替换,而它起作用的时间段就是这条边之后。
算答案明显可以主席树,所以这道题就解决啦。
#include<iostream> #include<cstdio> #define MN 200000 using namespace std; inline int read() { int x = 0 , f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){ if(ch == '-') f = -1; ch = getchar();} while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();} return x * f; } int n,m,k,type,last,fa[MN+5],c[MN+5][2],f[MN+5],p[MN+5],q[MN+5],top,mx[MN+5],L[MN+5],R[MN+5],rt[MN+5],cnt=0; struct node{int l,r,x;}T[MN*25]; bool rev[MN+5]; struct edge{int from,to;}e[MN+5]; inline bool isroot(int x){return c[fa[x]][0]!=x&&c[fa[x]][1]!=x;} inline void update(int x) { int l=c[x][0],r=c[x][1]; L[x]=f[x];R[x]=p[x]; mx[x]=max(p[x],f[x]); if(l) L[x]=L[l],mx[x]=max(mx[x],mx[l]); if(r) R[x]=R[r],mx[x]=max(mx[x],mx[r]); } void pushdown(int x) { if(x&&rev[x]) { int l=c[x][0],r=c[x][1]; rev[l]^=1;rev[r]^=1;rev[x]^=1; swap(f[l],p[l]);swap(L[l],R[l]); swap(f[r],p[r]);swap(L[r],R[r]); swap(c[x][0],c[x][1]); } } void rotate(int x) { int y=fa[x],z=fa[y],l=c[y][1]==x,r=l^1; if(!isroot(y)) c[z][c[z][1]==y]=x; fa[x]=z;fa[y]=x;fa[c[x][r]]=y; c[y][l]=c[x][r];c[x][r]=y; update(y);update(x); } void splay(int x) { q[top=1]=x; for(int t=fa[x];t;t=fa[t]) q[++top]=t; for(;top;--top) pushdown(q[top]); for(;!isroot(x);rotate(x)) if(!isroot(fa[x])) rotate((c[fa[fa[x]]][1]==fa[x]^c[fa[x]][1]==x)?x:fa[x]); } void access(int x) { for(int y=0;x;x=fa[y=x]) splay(x),c[x][1]=y,p[x]=L[y],update(x); } void link(int x,int y,int z) { access(x);splay(x);rev[x]^=1;swap(f[x],p[x]);swap(L[x],R[x]); access(y);c[y][1]=x;fa[x]=y;f[x]=p[y]=z; update(x);update(y); } void cut(int x,int y) { access(x);splay(x);rev[x]^=1;swap(f[x],p[x]);swap(L[x],R[x]); access(y);splay(y);c[y][0]=fa[x]=f[y]=p[x]=0; update(x);update(y); } void ins(int x,int nx,int k) { int l=0,r=m,mid; while(l<r) { mid=l+r>>1; if(k<=mid) { T[nx].r=T[x].r;T[nx].l=++cnt; x=T[x].l;nx=T[nx].l;r=mid; } else { T[nx].l=T[x].l;T[nx].r=++cnt; x=T[x].r;nx=T[nx].r;l=mid+1; } T[nx].x=T[x].x+1; } } int query(int x,int nx,int k) { int sum=0,l=0,r=m,mid; while(l<r) { mid=l+r>>1; if(k>mid) sum+=T[T[nx].l].x-T[T[x].l].x,x=T[x].r,nx=T[nx].r,l=mid+1; else x=T[x].l,nx=T[nx].l,r=mid; } return sum+T[nx].x-T[x].x; } int main() { n=read();m=read();k=read();type=read(); for(int i=1;i<=m;i++) e[i].from=read(),e[i].to=read(); for(int i=1;i<=m;i++) { int res=0,x=e[i].from,y=e[i].to; if(x!=y) { access(x);splay(x);rev[x]^=1;swap(f[x],p[x]);swap(L[x],R[x]); access(y);splay(y); if(!isroot(x)) res=mx[y],cut(e[m+1-res].from,e[m+1-res].to); link(x,y,m+1-i);ins(rt[i-1],rt[i]=++cnt,res?m+1-res:0); } else rt[i]=rt[i-1]; } for(int i=1;i<=k;i++) { int l=read()^(last*type),r=read()^(last*type); printf("%d ",last=n-query(rt[l-1],rt[r],l-1)); } return 0; }