把边的编号看成边权,维护每个状态对应的最大生成树,得到一个数组a[i],表示第i条边在这个过程中替换的是那条边,询问时看一下a[l,r]内啊有多少个小于l的算一下答案就好;代码参考:http://blog.csdn.net/thy_asdf/article/details/50518526
//lct不好处理边权,把一条边转成夹在两个点之间的点; #include<iostream> #include<cstring> #include<cmath> #include<cstdio> #include<algorithm> using namespace std; const int maxn=400010,maxt=10000010,inf=1e9; struct edg{ int u,v; }e[maxn]; struct node{ int l,r,v; }tr[maxt]; int n,m,k,tot,root[maxn],a[maxn],type,lastans; void insert(int t,int l,int r,int &x){ ++tot;tr[tot]=tr[x];x=tot; ++tr[tot].v; if(l==r)return; int mid=l+r>>1; if(t<=mid)insert(t,l,mid,tr[x].l); else insert(t,mid+1,r,tr[x].r); } int qs(int x,int y,int l,int r,int L,int R){ if(r<L||l>R||l>r)return 0; if(l>=L&&r<=R)return tr[y].v-tr[x].v; int mid=l+r>>1; return qs(tr[x].l,tr[y].l,l,mid,L,R)+qs(tr[x].r,tr[y].r,mid+1,r,L,R); } struct node2{ int ls,rs,fa,is_root; }tre[maxn]; int siz[maxn],mins[maxn],val[maxn],cnt,rev[maxn]; void update(int x){ mins[x]=x; if(val[mins[tre[x].ls]]<val[mins[x]])mins[x]=mins[tre[x].ls]; if(val[mins[tre[x].rs]]<val[mins[x]])mins[x]=mins[tre[x].rs]; } void flip(int x){swap(tre[x].ls,tre[x].rs);rev[x]^=1;} void pushdown(int x){if(rev[x])flip(tre[x].ls),flip(tre[x].rs),rev[x]^=1;} void relax(int x){if(tre[x].fa)relax(tre[x].fa);pushdown(x);} void rx(int x){ int y=tre[x].fa,z=tre[y].fa; tre[y].ls=tre[x].rs; if(tre[x].rs)tre[tre[x].rs].fa=y; tre[x].rs=y;tre[y].fa=x; tre[x].fa=z; if(z&&!tre[y].is_root){ if(tre[z].ls==y)tre[z].ls=x;else tre[z].rs=x; } if(tre[y].is_root)tre[x].is_root=1,tre[y].is_root=0; update(y);update(x); } void lx(int x){ int y=tre[x].fa,z=tre[y].fa; tre[y].rs=tre[x].ls; if(tre[x].ls)tre[tre[x].ls].fa=y; tre[x].ls=y;tre[y].fa=x; tre[x].fa=z; if(z&&!tre[y].is_root){ if(tre[z].ls==y)tre[z].ls=x;else tre[z].rs=x; } if(tre[y].is_root)tre[x].is_root=1,tre[y].is_root=0; update(y);update(x); } void splay(int x){ relax(x); while(!tre[x].is_root){ //cout<<"orz"<<endl; int y=tre[x].fa,z=tre[y].fa; if(tre[y].is_root){if(tre[y].ls==x)rx(x);else lx(x);} else{ if(tre[z].ls==y&&tre[y].ls==x){rx(y);rx(x);} else if(tre[z].ls==y&&tre[y].rs==x){lx(x);rx(x);} else if(tre[z].rs==y&&tre[y].ls==x){rx(x);lx(x);} else {lx(y);lx(x);} } } } void ace(int x){ int y=0; do{ splay(x); if(tre[x].rs)tre[tre[x].rs].is_root=1; tre[tre[x].rs=y].is_root=0; update(x); x=tre[y=x].fa; }while(x); } void makeroot(int x){ace(x);splay(x);flip(x);} void link(int x,int y){makeroot(x);tre[x].fa=y;} void cut(int x,int y){makeroot(x);ace(y);splay(y);tre[y].ls=tre[x].fa=0;tre[x].is_root=1;}//一开始最后这句话丢了; int findrt(int x){ace(x);splay(x);for(;tre[x].ls;x=tre[x].ls);return x;} int query(int x,int y){makeroot(x);ace(y);splay(y);return mins[y];} void pre(){ for(int i=1;i<=n+m;++i)tre[i].is_root=1; cnt=n; for(int i=1;i<=m;++i){ int u=e[i].u,v=e[i].v; if(u==v){a[i]=i;continue;} if(findrt(u)==findrt(v)){ int cp=query(u,v),x=val[cp]; a[i]=x;cut(e[x].u,cp);cut(e[x].v,cp); } ++cnt;mins[cnt]=cnt;val[cnt]=i;link(u,cnt);link(v,cnt); } for(int i=1;i<=m;++i){ root[i]=root[i-1];insert(a[i],0,m,root[i]); } } int main(){ cin>>n>>m>>k>>type; val[0]=inf; for(int i=1;i<=n;++i)mins[i]=i,val[i]=inf; for(int i=1;i<=m;++i)scanf("%d%d",&e[i].u,&e[i].v); pre(); int l,r; for(int i=1;i<=k;++i){ scanf("%d%d",&l,&r); if(type)l^=lastans,r^=lastans; printf("%d\n",lastans=(n-qs(root[l-1],root[r],0,m,0,l-1))); } return 0; }