题解:
貌似是LCT的套路题?
就是建主席树,然后每次形成环时将环中的第一条边送给新边作标记。
维护这种恶心东西当然用LCT了。
这道题还不同于裸一点的LCT题。本题要对于每条边新建一个节点(类似圆方树),然后将时间信息放到新建节点上。
最后每次查询只需要查标记小于l的边就行了。
因为标记小于l说明踢掉了一条不属于当前集合的边,最后剩下的只有有用的边了。
每条有用的边会干掉一个联通块。
代码:
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define N 200050 inline int rd() { int f=1,c=0;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){c=10*c+ch-'0';ch=getchar();} return f*c; } int n,m,K,typ,ans; struct EG { int f,t; }e[N]; struct segtree { int rt[N],tot,ls[40*N],rs[40*N],v[40*N]; void update(int u) { v[u] = v[ls[u]] + v[rs[u]]; } void insert(int l,int r,int &u,int k,int qx) { u = ++tot; ls[u] = ls[k],rs[u] = rs[k],v[u] = v[k]+1; if(l==r)return ; int mid = (l+r)>>1; if(qx<=mid)insert(l,mid,ls[u],ls[k],qx); else insert(mid+1,r,rs[u],rs[k],qx); } int query(int l,int r,int ul,int ur,int ql,int qr) { if(l==ql&&r==qr)return v[ur]-v[ul]; int mid = (l+r)>>1; if(qr<=mid)return query(l,mid,ls[ul],ls[ur],ql,qr); else if(ql>mid)return query(mid+1,r,rs[ul],rs[ur],ql,qr); else return query(l,mid,ls[ul],ls[ur],ql,mid)+query(mid+1,r,rs[ul],rs[ur],mid+1,qr); } }tr1; struct LCT { int fa[N*2],ch[N*2][2],v[N*2],mn[N*2]; bool res[N*2]; bool isroot(int x) { return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x; } void update(int x) { mn[x] = x; if(v[mn[ch[x][0]]]<v[mn[x]])mn[x]=mn[ch[x][0]]; if(v[mn[ch[x][1]]]<v[mn[x]])mn[x]=mn[ch[x][1]]; } void reser(int x) { res[x]^=1; swap(ch[x][0],ch[x][1]); } void pushdown(int x) { if(res[x]) { reser(ch[x][0]); reser(ch[x][1]); res[x]=0; } } int st[N],tl; void down(int x) { st[tl=1]=x; while(!isroot(x))x=fa[x],st[++tl]=x; while(tl)pushdown(st[tl]),tl--; } void rotate(int x) { int y = fa[x],z = fa[y],k = (ch[y][1]==x); if(!isroot(y))ch[z][ch[z][1]==y]=x; fa[x] = z; ch[y][k] = ch[x][!k], fa[ch[x][!k]] = y; ch[x][!k] = y,fa[y] = x; update(y),update(x); } void splay(int x) { down(x); while(!isroot(x)) { int y = fa[x],z = fa[y]; if(!isroot(y)) (ch[y][1]==x)^(ch[z][1]==y)?rotate(x):rotate(y); rotate(x); } } void access(int x) { int y = 0; while(x) { splay(x); ch[x][1]=y; update(x); y = x,x = fa[x]; } } void mtr(int x) { access(x); splay(x); reser(x); } int findrt(int x) { access(x),splay(x); while(ch[x][0])x=ch[x][0]; return x; } void link(int x,int y) { mtr(x); fa[x]=y; } void cut(int x,int y) { mtr(x); access(y); splay(y); ch[y][0]=fa[x]=0; update(y); } int query(int x,int y) { mtr(x); access(y); splay(y); return mn[y]; } }tr2; int ntr[N]; void init() { for(int f,t,i=1;i<=m;i++) { f = e[i].f,t = e[i].t; if(f==t) { ntr[i] = i; continue; } if(tr2.findrt(f)==tr2.findrt(t)) { int tmp = tr2.query(f,t); int edg = tr2.v[tmp]; tr2.cut(e[edg].f,tmp); tr2.cut(e[edg].t,tmp); ntr[i] = edg; } tr2.v[i+n] = i; tr2.link(i+n,f); tr2.link(i+n,t); } for(int i=1;i<=m;i++) tr1.insert(0,m,tr1.rt[i],tr1.rt[i-1],ntr[i]); } int main() { n = rd(),m = rd(),K = rd(),typ = rd(); for(int f,t,i=1;i<=m;i++) { f = rd(),t = rd(); e[i].f=f,e[i].t=t; } tr2.v[0]=0x3f3f3f3f; for(int i=1;i<=n+m;i++) { tr2.mn[i]=i; tr2.v[i]=0x3f3f3f3f; } init(); for(int l,r,i=1;i<=K;i++) { l=rd(),r=rd(); if(typ)l^=ans,r^=ans; if(l>r)swap(l,r); ans = n-tr1.query(0,m,tr1.rt[l-1],tr1.rt[r],0,l-1); printf("%d\n",ans); } return 0; }