经典问题。强制在线的话非常复杂。
考虑离线。
每条边的存在时间是一个区间,因此按时间建立一颗线段树,将每条边插入,拆成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