解决在树上加边或删边后的两点联通性问题,线段树线段表示时间,结点存储这个时间段内存在的边,线段树使用区间修改,单点查询.查询时先把每个结点储存的边的两端利用并查集合并,离开时需要利用栈进行撤销.
#include<iostream>
#include<cstdio>
#include<cstring>
#include<map>
#include<vector>
#include<stack>
using namespace std;
typedef pair<int,int> pii;
int n,m;
int p[10010],rk[10010];
vector<pii>edge[200010*4];
struct Query
{
int u,v,t;
Query(int a=0,int b=0,int c=0):u(a),v(b),t(c){}
}q[200010];
struct node
{
int a,b,c,d;
node(int a1,int b1,int c1,int d1):a(a1),b(b1),c(c1),d(d1){}
};
stack<node>st;
map<pii,int>mp;
int ans[200010];
void add(int now,int l,int r,int x,int y,pii z)
{
if(x<=l&&r<=y)
{
edge[now].push_back(z);
return;
}
int mid=(l+r)>>1;
if(y<=mid)
add(now<<1,l,mid,x,y,z);
else if(x>mid)
add(now<<1|1,mid+1,r,x,y,z);
else
{
add(now<<1,l,mid,x,y,z);
add(now<<1|1,mid+1,r,x,y,z);
}
}
int find(int x)
{return p[x]==x?x:find(p[x]);}
void undo()
{
node tmp=st.top();st.pop();
p[tmp.b]=tmp.b;
rk[tmp.a]=tmp.c;
}
void query(int now,int l,int r)
{
for(int i=0;i<edge[now].size();++i)
{
// cout<<edge[now][i].first<<' '<<edge[now][i].second<<endl;
int x=find(edge[now][i].first),y=find(edge[now][i].second);
if(rk[x]<rk[y])swap(x,y);
st.push(node(x,y,rk[x],rk[y]));
p[y]=x;
if(rk[x]==rk[y])rk[x]++;
}
if(l==r)
{
int x=find(q[l].u),y=find(q[l].v);
// cout<<q[l][i].u<<' '<<q[l][i].v<<endl;
if(x==y)
ans[q[l].t]=1;
else
ans[q[l].t]=2;
for(int i=0;i<edge[now].size();++i)undo();
return;
}
int mid=(l+r)>>1;
query(now<<1,l,mid);
query(now<<1|1,mid+1,r);
for(int i=0;i<edge[now].size();++i)undo();
}
int main()
{
// freopen("1.txt","r",stdin);
cin>>n>>m;
for(int i=1;i<=n;++i)p[i]=i;
for(int i=1;i<=m;++i)
{
char s[16];int x,y;
scanf("%s%d%d",s,&x,&y);
if(s[0]=='Q')
{
q[i]=Query(x,y,i);
}
else if(s[0]=='C')
{
if(x>y)swap(x,y);
pii tmp;tmp.first=x,tmp.second=y;
if(mp.find(tmp)==mp.end())
{
mp.insert({tmp,i});
}
}
else
{
if(x>y)swap(x,y);
pii tmp;tmp.first=x,tmp.second=y;
map<pii,int>::iterator it=mp.find(tmp);
if(it==mp.end())
continue;
// cout<<1<<endl;
add(1,1,m,it->second,i,tmp);
mp.erase(it);
}
}
for(map<pii,int>::iterator it=mp.begin();it!=mp.end();++it)
add(1,1,m,it->second,m,it->first);
query(1,1,m);
for(int i=1;i<=m;++i)
{
if(ans[i]==1)
printf("Yes\n");
else if(ans[i]==2)
printf("No\n");
}
return 0;
}