BZOJ 3514 GERALD07加强版 (LCT+主席树)
题目大意:给定n个点m条边无向图,每次询问求当图中有编号为[L,R]的边时,整个图的联通块个数,强制在线
神题!(发现好久以前的题解没有写完诶)
我们要求图中联通块的个数,似乎不可搞啊。
联通块个数=n-树边条数!
考虑每条边的贡献,我们按编号从小到大暴力枚举每一条边。
考虑用$LCT$维护森林。
设新加入的这条边编号为$e$,连接了$x,y$两个点
如果$x,y$原来不连通,说明加入$e$会让图中多一条树边。边e对$L\in [1,e],R\geq e$的图$[L,R]$产生一点贡献
如果$x,y$原来就联通,说明加入$e$会产生环,并不会影响联通块个数。我们找出$e$所在环里编号最小的边$x$
当$L\leq x$时,删掉边$x$,图$[L,R]$的树边个数不变。
当$L>x$时,删掉边$x$,会让图$[L,R]$少一条树边。那么边$x$会对$L\in[x+1,e],R\geq e$的的图$[L,R]$产生一点贡献
如何处理询问?我们可以用主席树,主席树不同的根作为右端点,线段树维护对左端点的贡献。每次查询,主席树相减,然后单点查询
如何维护贡献?主席树上打差分实现区间修改
如何维护编号最小的边?把边转化成点扔到$LCT$里就行啦
1 #include <queue> 2 #include <vector> 3 #include <cstdio> 4 #include <cstring> 5 #include <algorithm> 6 #define N1 401000 7 #define M1 201000 8 #define S1 (N1<<1) 9 #define T1 (N1<<2) 10 #define ll long long 11 #define uint unsigned int 12 #define rint register int 13 #define ull unsigned long long 14 #define dd double 15 #define il inline 16 #define inf 1000000000 17 using namespace std; 18 19 int gint() 20 { 21 int ret=0,fh=1;char c=getchar(); 22 while(c<'0'||c>'9'){if(c=='-')fh=-1;c=getchar();} 23 while(c>='0'&&c<='9'){ret=ret*10+c-'0';c=getchar();} 24 return ret*fh; 25 } 26 int n,m,T,type; 27 struct Edge{ 28 int x[M1],y[M1],cte; 29 void ae(int u,int v) 30 {cte++;x[cte]=u,y[cte]=v;} 31 }E; 32 struct SEG{ 33 int ls[N1*40],rs[N1*40],sum[N1*40],root[N1],tot; 34 void pushup(int rt){sum[rt]=sum[ls[rt]]+sum[rs[rt]];} 35 void build(int l,int r,int &rt) 36 { 37 int mid=(l+r)>>1; rt=++tot; 38 if(l==r) return; 39 build(l,mid,ls[rt]); 40 build(mid+1,r,rs[rt]); 41 } 42 void update(int x,int l,int r,int r1,int &r2,int w) 43 { 44 if((!r2)||(r1==r2)){r2=++tot,sum[r2]=sum[r1],ls[r2]=ls[r1],rs[r2]=rs[r1];} 45 if(l==r) {sum[r2]+=w; return;} int mid=(l+r)>>1; 46 if(x<=mid) update(x,l,mid,ls[r1],ls[r2],w); 47 else update(x,mid+1,r,rs[r1],rs[r2],w); 48 pushup(r2); 49 } 50 int query(int L,int R,int l,int r,int rt) 51 { 52 if(!rt||L>R) return 0; 53 if(L<=l&&r<=R) return sum[rt]; 54 int mid=(l+r)>>1,ans=0; 55 if(L<=mid) ans+=query(L,R,l,mid,ls[rt]); 56 if(R>mid) ans+=query(L,R,mid+1,r,rs[rt]); 57 return ans; 58 } 59 }s; 60 namespace lct{ 61 int ch[N1][2],fa[N1],mi[N1],id[N1],rev[N1],tot; 62 int idf(int x){return ch[fa[x]][0]==x?0:1;} 63 int isroot(int x){return (ch[fa[x]][0]==x||ch[fa[x]][1]==x)?0:1;} 64 void pushup(int x){mi[x]=min(x,min(mi[ch[x][0]],mi[ch[x][1]]));} 65 void revers(int x){swap(ch[x][0],ch[x][1]),rev[x]^=1;} 66 void pushdown(int x){if(rev[x]){revers(ch[x][0]),revers(ch[x][1]),rev[x]^=1;}} 67 void rot(int x) 68 { 69 int y=fa[x],ff=fa[y],px=idf(x),py=idf(y); 70 if(!isroot(y)) ch[ff][py]=x; fa[x]=ff; 71 fa[ch[x][px^1]]=y,ch[y][px]=ch[x][px^1]; 72 ch[x][px^1]=y,fa[y]=x; 73 pushup(y),pushup(x); 74 } 75 int stk[N1],tp; 76 void splay(int x) 77 { 78 int y=x; stk[++tp]=x; 79 while(!isroot(y)){stk[++tp]=fa[y],y=fa[y];} 80 while(tp){pushdown(stk[tp--]);} 81 while(!isroot(x)) 82 { 83 y=fa[x]; 84 if(isroot(y)) rot(x); 85 else if(idf(y)==idf(x)) rot(y),rot(x); 86 else rot(x),rot(x); 87 } 88 } 89 void access(int x){for(int y=0;x;y=x,x=fa[x]) splay(x),ch[x][1]=y,pushup(x);} 90 void mkroot(int x){access(x),splay(x),revers(x);} 91 void split(int x,int y){mkroot(x),access(y),splay(y);} 92 int fdroot(int x){access(x),splay(x);while(ch[x][0])pushdown(ch[x][0]),x=ch[x][0];return x;} 93 void cut(int x,int y){split(x,y);fa[x]=ch[y][0]=0,pushup(y);} 94 void link(int x,int y){split(x,y);fa[x]=y;} 95 //int isconn(int x,int y){split(x,y);if(!ch[x][1]&&fa[x]=y&&ch[y][0]==x) return 1;} 96 void solve(int x,int y,int e) 97 { 98 split(x+m,y+m); 99 if(x==y){ 100 int r1=s.root[e-1],r2=s.root[e]=++s.tot; 101 s.sum[r2]=s.sum[r1],s.ls[r2]=s.ls[r1],s.rs[r2]=s.rs[r1]; 102 }else if(fdroot(y+m)!=x+m){ 103 s.update(1,1,m,s.root[e-1],s.root[e],1); 104 if(e<m) s.update(e+1,1,m,s.root[e-1],s.root[e],-1); 105 }else{ 106 int id=mi[y+m],xx=E.x[id],yy=E.y[id]; 107 cut(id,xx+m); cut(id,yy+m); 108 s.update(id+1,1,m,s.root[e-1],s.root[e],1); 109 if(e<m) s.update(e+1,1,m,s.root[e-1],s.root[e],-1); 110 } 111 link(e,x+m),link(e,y+m); 112 } 113 }; 114 int tot; 115 116 int main() 117 { 118 int i,j,x,y,Q,sx,sy,ans=0; tot=n+m; 119 scanf("%d%d%d%d",&n,&m,&Q,&type); 120 for(j=1;j<=m;j++) x=gint(), y=gint(), E.ae(x,y); 121 s.build(1,m,s.root[0]); 122 for(lct::mi[0]=inf,i=1;i<=n+m;i++) lct::mi[i]=i; 123 for(j=1;j<=m;j++) 124 { 125 x=E.x[j]; y=E.y[j]; 126 lct::solve(x,y,j); 127 } 128 for(j=1;j<=Q;j++) 129 { 130 x=gint(), y=gint(); 131 if(type) x^=ans,y^=ans; 132 sx=s.query(1,x,1,m,s.root[x-1]); 133 sy=s.query(1,x,1,m,s.root[y]); 134 ans=n-(sy-sx); 135 printf("%d\n",ans); 136 } 137 return 0; 138 } 139