BZOJ3514 : Codechef MARCH14 GERALD07加强版
以边编号为权值
用Link-cut Tree维护最大生成树
对于新加的第i条边(u,v)
a[i]表示当a[i]这条边加入后连通块个数会减少
若u==v则a[i]=m
若u与v不连通则连上,a[i]=0
若u与v连通则a[i]为u,v路径上最小值,将那条边断开,连上这条边
查询[l,r]等价于查询[l,r]里有多少a[i]<l
主席树维护
时间复杂度$O((m+k)\log m)$
#include<cstdio> #define N 400010 #define E 200010 #define M 4000010 int f[N],son[N][2],val[N],min[N],tmp[N];bool rev[N]; inline void read(int&a){char c;while(!(((c=getchar())>='0')&&(c<='9')));a=c-'0';while(((c=getchar())>='0')&&(c<='9'))(a*=10)+=c-'0';} inline void swap(int&a,int&b){int c=a;a=b;b=c;} inline int Min(int a,int b){return a<b?a:b;} inline bool isroot(int x){return !f[x]||son[f[x]][0]!=x&&son[f[x]][1]!=x;} inline void rev1(int x){if(!x)return;swap(son[x][0],son[x][1]);rev[x]^=1;} inline void pb(int x){if(rev[x])rev1(son[x][0]),rev1(son[x][1]),rev[x]=0;} inline void up(int x){min[x]=Min(val[x],Min(min[son[x][0]],min[son[x][1]]));} inline void rotate(int x){ int y=f[x],w=son[y][1]==x; son[y][w]=son[x][w^1]; if(son[x][w^1])f[son[x][w^1]]=y; if(f[y]){ int z=f[y]; if(son[z][0]==y)son[z][0]=x; if(son[z][1]==y)son[z][1]=x; } f[x]=f[y];f[y]=x;son[x][w^1]=y;up(y); } inline void splay(int x){ int s=1,i=x,y;tmp[1]=i; while(!isroot(i))tmp[++s]=i=f[i]; while(s)pb(tmp[s--]); while(!isroot(x)){ y=f[x]; if(!isroot(y)){if((son[f[y]][0]==y)^(son[y][0]==x))rotate(x);else rotate(y);} rotate(x); } up(x); } inline void access(int x){for(int y=0;x;y=x,x=f[x])splay(x),son[x][1]=y,up(x);} inline int root(int x){access(x);splay(x);while(son[x][0])x=son[x][0];return x;} inline void makeroot(int x){access(x);splay(x);rev1(x);} inline void link(int x,int y){makeroot(x);f[x]=y;access(x);} inline void cutf(int x){access(x);splay(x);f[son[x][0]]=0;son[x][0]=0;up(x);} inline void cut(int x,int y){makeroot(x);cutf(y);} inline int ask(int x,int y){makeroot(x);access(y);splay(y);return min[y];} int n,m,i,k,type,x,y,u[E],v[E],a[E],tot,l[M],r[M],sum[M],head[E],last; int ins(int x,int a,int b,int c){ int y=++tot; sum[y]=sum[x]+1; if(a==b)return y; int mid=(a+b)>>1; if(c<=mid)l[y]=ins(l[x],a,mid,c),r[y]=r[x];else l[y]=l[x],r[y]=ins(r[x],mid+1,b,c); return y; } int query(int x,int a,int b,int c){ if(!x)return 0; if(b<=c)return sum[x]; int mid=(a+b)>>1,t=query(l[x],a,mid,c); if(c>mid)t+=query(r[x],mid+1,b,c); return t; } int main(){ read(n);read(m);read(k);read(type); for(i=0;i<=n;i++)val[i]=min[i]=1000000000; for(i=1;i<=m;i++)val[i+n]=min[i+n]=i; for(i=1;i<=m;i++){ read(u[i]);read(v[i]); if(u[i]==v[i])a[i]=m; else if(root(u[i])==root(v[i]))a[i]=ask(u[i],v[i]),cut(u[a[i]],a[i]+n),cut(v[a[i]],a[i]+n),link(u[i],i+n),link(v[i],i+n); else link(u[i],i+n),link(v[i],i+n); } for(i=1;i<=m;i++)head[i]=ins(head[i-1],0,m,a[i]); while(k--){ read(x),read(y); if(type)x^=last,y^=last; printf("%d\n",last=n-query(head[y],0,m,x-1)+query(head[x-1],0,m,x-1)); } return 0; }