也是比较久的一个坑了。
首先考虑一下联通块个数=总点数-有贡献的边数,即没有形成环的边数。
那么采用一种数据结构题非常经典的做法了,pre[i]表示边i加入后应该弹出哪条边。
如果支持离线的话,按l排个序,想bzoj1878一样,每次跳就可以了。
强制在线,每次询问[l,r]中pre[i]在[0,l-1]中的边数,这个问题用主席树解决。
时限卡得好紧
#include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<algorithm> #include<iostream> #define maxn 200010 using namespace std; struct yts { int x,y; }e[maxn]; int pre[maxn],root[maxn],cnt[maxn*20],lch[maxn*20],rch[maxn*20]; bool rev[maxn*2]; int ch[maxn*2][2],fa[maxn*2],val[maxn*2],mn[maxn*2]; int n,m,tot,mx,typ,T; int dir(int x) { return x==ch[fa[x]][1]; } int isroot(int x) { return !((x==ch[fa[x]][0]) || (x==ch[fa[x]][1])); } int find_root(int x) { while (fa[x]) x=fa[x]; return x; } void reverse(int x) { swap(ch[x][0],ch[x][1]);rev[x]^=1; } void push_down(int x) { if (rev[x]) { if (ch[x][0]) reverse(ch[x][0]); if (ch[x][1]) reverse(ch[x][1]); rev[x]=0; } } void push_up(int x) { mn[x]=x; if (val[mn[ch[x][0]]]<val[mn[x]]) mn[x]=mn[ch[x][0]]; if (val[mn[ch[x][1]]]<val[mn[x]]) mn[x]=mn[ch[x][1]]; } void rotate(int x) { int y=fa[x],z=fa[y],b=dir(x),a=ch[x][!b]; if (!isroot(y)) { int c=dir(y);ch[z][c]=x; } fa[x]=z;fa[y]=x;ch[x][!b]=y;ch[y][b]=a; if (a!=0) fa[a]=y; push_up(y);push_up(x); } void down(int x) { if (!isroot(x)) down(fa[x]); push_down(x); } void splay(int x) { down(x); while (!isroot(x)) { int y=fa[x]; if (isroot(y)) rotate(x); else { int b=dir(x),c=dir(y); if (b^c) { rotate(x);rotate(x); } else { rotate(y);rotate(x); } } } } void access(int x) { for (int y=0;x;y=x,x=fa[x]) { splay(x); ch[x][1]=y; push_up(x); } } void make_root(int x) { access(x); splay(x); reverse(x); } void cut(int x,int y) { make_root(x); access(x); splay(y); fa[y]=0; } void link(int x,int y) { make_root(x); fa[x]=y; } int query(int x,int y) { make_root(x); access(y); splay(y); return mn[y]; } int modify(int pre,int l,int r,int x) { int now=++tot; if (l==r) { lch[now]=rch[now]=0;cnt[now]=cnt[pre]+1; } else { int mid=(l+r)/2; if (x<=mid) { rch[now]=rch[pre];lch[now]=modify(lch[pre],l,mid,x); } else { lch[now]=lch[pre];rch[now]=modify(rch[pre],mid+1,r,x); } cnt[now]=cnt[lch[now]]+cnt[rch[now]]; } return now; } int query(int root1,int root2,int l,int r,int x) { if (r==x) return cnt[root2]-cnt[root1]; int mid=(l+r)/2; if (x<=mid) return query(lch[root1],lch[root2],l,mid,x); else return cnt[lch[root2]]-cnt[lch[root1]]+query(rch[root1],rch[root2],mid+1,r,x); } int main() { scanf("%d%d%d%d",&n,&m,&T,&typ); for (int i=0;i<=n+m;i++) fa[i]=0,val[i]=m+1,mn[i]=i; for (int i=1;i<=m;i++) { int x,y; scanf("%d%d",&x,&y); e[i].x=x;e[i].y=y; if (x==y) {pre[i]=i;continue;} if (find_root(x)==find_root(y)) { int t=query(x,y); pre[i]=val[t]; cut(e[t-n].x,t);cut(e[t-n].y,t); } val[n+i]=i;mn[n+i]=n+i; link(x,n+i);link(y,n+i); } for (int i=1;i<=m;i++) root[i]=modify(root[i-1],1,m+1,pre[i]+1); int ans=0; while (T--) { int l,r; scanf("%d%d",&l,&r); if (typ) l^=ans,r^=ans; ans=n-query(root[l-1],root[r],1,m+1,l); printf("%d\n",ans); } return 0; }