标签:
经典问题。强制在线的话非常复杂。
考虑离线。
每条边的存在时间是一个区间,因此按时间建立一颗线段树,将每条边插入,拆成log条边。然后dfs线段树,每次并查集合并当前节点的所有边,到叶子节点时回答询问,回溯时撤销并查集的修改。
带撤销的并查集不能路径压缩,要按秩合并。
#include<bits/stdc++.h> #define N 200005 #define M (l+r>>1) #define P (k<<1) #define S (k<<1|1) #define L l,M,P #define R M+1,r,S #define Z int l=1,int r=q,int k=1 #define u first #define v second using namespace std; struct io_t{ operator int(){ int x; scanf("%d",&x); return x; } }it; int n=it,m=it,s[N],t[N]; int p[N],u[N],v[N],j,q; char d[N]; typedef pair<int,int> vec; vec f[N],e[N]; vector<vec> a[1<<18]; int find(int i){ return p[i]==i ?i:find(p[i]); } void add(vec v,int s,int t,Z){ if(s<=l&&r<=t) a[k].push_back(v); else{ if(s<=M) add(v,s,t,L); if(t>M) add(v,s,t,R); } } void dfs(Z){ for(int j=0;j!=a[k].size();++j){ vec* i=&a[k][j]; i->u=find(i->u); i->v=find(i->v); if(i->u^i->v){ if(u[i->u]<u[i->v]) swap(i->u,i->v); p[i->v]=i->u; u[i->u]+=u[i->v]; } } if(l==r) d[l]^81?0:v[l] =find(f[l].u) ^find(f[l].v); else{ dfs(L);dfs(R); } for(int j=a[k].size()-1;~j;--j){ vec* i=&a[k][j]; if(i->u^i->v){ p[i->v]=i->v; u[i->u]-=u[i->v]; } } } int main(){ for(int i=1;i<=n;++i) u[p[i]=i]=1; for(int i=1;i<=m;++i) e[i]=vec(it,it); q=it; for(int i=1;i<=q;++i){ scanf(" %c%d",d+i,&j); if(d[i]==68) t[j]?0:t[j]=i; if(d[i]==81) f[i]=vec(j,it); if(d[i]==73&&++m){ s[m]=i; e[m]=vec(j,it); } } for(int i=1;i<=m;++i) add(e[i], s[i],t[i]?t[i]:q); dfs(); for(int i=1;i<=q;++i) if(d[i]==81) puts(v[i]?"No":"Yes"); }
标签:
原文地址:http://www.cnblogs.com/f321dd/p/5813830.html