BZOJ3514 Codechef MARCH14 GERALD07加强版 LCT+可持久化线段树
联通块个数等于 $n$ 减掉关键边个数.
这里定义关键边为:能连接两个连通块的边.
由于强制在线,我们考虑用一种数据结构维护以 $r$ 为右端点的答案.
考虑已经构建好 $1$ ~ $r-1$ 的图,那么假如 $r$ 时分两种情况:
1. $r$ 连接的两个点没有联通,那么就将这两个点连上.
2. $r$ 连接的两个点已经联通,那么以 $r$ 为询问的右端点的话不论 $l$ 取什么 $u,v$ 都联通.
为了后面的维护,关键边的开始时间显然越靠后越好,那么在情况 $2$ 中直接删掉开始时间最小的边即可.
关键边用主席树来维护贡献,询问的时候在主席树中查询区间和即可.
#include <bits/stdc++.h> #define N 400005 #define inf 1000000000 #define setIO(s) freopen(s".in","r",stdin) , freopen(s".out","w",stdout) using namespace std; int rt[N]; struct Edge { int u,v,c; Edge(int u=0,int v=0,int c=0):u(u),v(v),c(c){} }e[N]; struct Union_Find_set { int p[N]; void init() { for(int i=0;i<N;++i) p[i]=i; } int find(int x) { return p[x]==x?x:p[x]=find(p[x]); } int merge(int x,int y) { x=find(x),y=find(y); if(x!=y) { p[x]=y; return 1; } else { return 0; } } }ufs; struct Link_Cut_Tree { #define lson t[x].ch[0] #define rson t[x].ch[1] int sta[N]; struct Node { int ch[2],f,min,id,val,rev; }t[N]; int get(int x) { return t[t[x].f].ch[1]==x; } int isrt(int x) { return !(t[t[x].f].ch[0]==x||t[t[x].f].ch[1]==x); } void pushup(int x) { t[x].min=t[x].val,t[x].id=x; if(lson&&t[lson].min<t[x].min) t[x].min=t[lson].min,t[x].id=t[lson].id; if(rson&&t[rson].min<t[x].min) t[x].min=t[rson].min,t[x].id=t[rson].id; } void mark(int x) { if(x) t[x].rev^=1,swap(lson,rson); } void pushdown(int x) { if(x&&t[x].rev) { t[x].rev=0; if(lson) mark(lson); if(rson) mark(rson); } } void rotate(int x) { int old=t[x].f,fold=t[old].f,which=get(x); if(!isrt(old)) t[fold].ch[t[fold].ch[1]==old]=x; t[old].ch[which]=t[x].ch[which^1],t[t[old].ch[which]].f=old; t[x].ch[which^1]=old,t[old].f=x,t[x].f=fold; pushup(old),pushup(x); } void splay(int x) { int v=0,u=x,fa; for(sta[++v]=u;!isrt(u);u=t[u].f) sta[++v]=t[u].f; for(;v;--v) pushdown(sta[v]); for(u=t[u].f;(fa=t[x].f)!=u;rotate(x)) if(t[fa].f!=u) rotate(get(fa)==get(x)?fa:x); } void Access(int x) { for(int y=0;x;y=x,x=t[x].f) splay(x),rson=y,pushup(x); } void makeroot(int x) { Access(x),splay(x),mark(x); } void split(int x,int y) { makeroot(x),Access(y),splay(y); } void link(int x,int y) { makeroot(x),t[x].f=y; } void cut(int x,int y) { makeroot(x),Access(y),splay(y); t[y].ch[0]=t[x].f=0; pushup(y); } #undef lson #undef rson }lct; struct Segment_Tree { int tot; int lson[N*20],rson[N*20],sum[N*20]; int update(int x,int l,int r,int p,int d) { int oo=++tot; lson[oo]=lson[x],rson[oo]=rson[x],sum[oo]=sum[x]+d; if(l==r) return oo; int mid=(l+r)>>1; if(p<=mid) lson[oo]=update(lson[x],l,mid,p,d); else rson[oo]=update(rson[x],mid+1,r,p,d); return oo; } int query(int x,int l,int r,int L,int R) { if(!x) return 0; if(l>=L&&r<=R) return sum[x]; int mid=(l+r)>>1,re=0; if(L<=mid) re+=query(lson[x],l,mid,L,R); if(R>mid) re+=query(rson[x],mid+1,r,L,R); return re; } }tr; int main() { // setIO("input"); int n,m,i,j,k,ty; scanf("%d%d%d%d",&n,&m,&k,&ty); lct.t[0].val=inf; for(i=1;i<=n;++i) lct.t[i].val=inf,lct.pushup(i); ufs.init(); for(i=1;i<=m;++i) { scanf("%d%d",&e[i].u,&e[i].v); int u=e[i].u; int v=e[i].v; int _new=i+n; rt[i]=rt[i-1]; if(u==v) { continue; } rt[i]=tr.update(rt[i-1],1,m,i,1); if(ufs.merge(u,v)) { lct.t[_new].val=i; lct.pushup(_new); lct.link(u,_new); lct.link(_new,v); } else { lct.split(u,v); int cc=lct.t[v].id; lct.cut(cc, e[cc-n].u); lct.cut(cc, e[cc-n].v); rt[i]=tr.update(rt[i],1,m,cc-n,-1); lct.t[_new].val=i; lct.pushup(_new); lct.link(_new, u); lct.link(_new, v); } } int lastans=0; for(i=1;i<=k;++i) { int l,r; scanf("%d%d",&l,&r); if(ty) { l^=lastans; r^=lastans; if(l>r) swap(l,r); } lastans=n-tr.query(rt[r],1,m,l,r); printf("%d\n",lastans); } return 0; }