题目链接:https://nanti.jisuanke.com/t/42576
题目大意:
思路:可撤销并查集
我们把操作建立成一个时间树。然后就可以在树上可撤销并查集。
对于操作3:我们新开个点作为镜像代替a,连向b。和题目uva11987类似。
#include<bits/stdc++.h>
#define LL long long
using namespace std;
struct node{
int id;
int form, to, x, y;
}sk[2000005];
int top=0;
struct Dsu{
//p元素所在集合全部元素的和。
//p元素集合的元素个数
int a[2000005];
int f[2000005], sum[2000005], num[2000005];
int id[2000005];//是否删除-1 镜像节点的id
int tot;//新节点
void init(int n){
top=0;
for(int i=1; i<=n; i++){
f[i]=-1; sum[i]=a[i];
num[i]=1; id[i]=0;
}
tot=n;
}
int fd(int x){
if(f[x]==-1) return x;
return fd(f[x]);
}
//删除x节点
void Delete(int x){
if(id[x]==-1) return ;
int fx=id[x]?fd(id[x]):fd(x);
sk[++top]=node{3, x, id[x], fx};
id[x]=-1;
sum[fx]--, num[fx]--;
}
//连接x, y集合
int link(int x, int y){
if(id[x]==-1||id[y]==-1) return 0;
int fx=id[x]?fd(id[x]):fd(x);
int fy=id[y]?fd(id[y]):fd(y);
if(fx==fy) return 0;
if(sum[fx]>=sum[fy]){
sk[++top]=node{1, fy, fx};
sum[fx]+=sum[fy];
num[fx]+=num[fy];
f[fy]=fx;
}
else{
sk[++top]=node{1, fx, fy};
sum[fy]+=sum[fx];
num[fy]+=num[fx];;
f[fx]=fy;
}
return 1;
}
//把x节点移到y在的集合
int movex(int x, int y){
if(id[x]==-1||id[y]==-1) return 0;
int fx=id[x]?fd(id[x]):fd(x);
int fy=id[y]?fd(id[y]):fd(y);
if(fx==fy) return 0;
sk[++top]=node{2, fx, fy, x, id[x]};
id[x]=++tot;
f[id[x]]=fy;
sum[fx]-=a[x]; num[fx]--;
sum[fy]+=a[x]; num[fy]++;
return 1;
}
//回退到sk。size()==pos的时间点
void revoke(int pos){
while(top>pos){
if(sk[top].id==1){
node t=sk[top]; top--;
f[t.form]=-1;
sum[t.to]-=sum[t.form];
num[t.to]-=num[t.form];
}
else if(sk[top].id==2){
node t=sk[top]; top--;
f[tot]=0;
id[t.x]=t.y; --tot;
sum[t.form]+=a[t.x]; num[t.form]++;
sum[t.to]-=a[t.x]; num[t.to]--;
}
else{
node t=sk[top]; top--;
id[t.form]=t.to;
sum[t.x]++, num[t.x]++;
}
}
}
}T;
struct Q{
int op;
int x, y;
}e[1000005];
vector<int> G[1000005];
int ans[1000005];
void DFS(int u){
if(e[u].op==1){
if(T.id[e[u].x]==-1||T.id[e[u].y]==-1){}
else{
T.link(e[u].x, e[u].y);
}
}
else if(e[u].op==2){
T.Delete(e[u].x);
}
else if(e[u].op==3){
T.movex(e[u].x, e[u].y);
}
else if(e[u].op==4){
if(T.id[e[u].x]==-1||T.id[e[u].y]==-1){
ans[u]=-2;
}
else{
int x=e[u].x, y=e[u].y;
int fx=T.id[x]?T.fd(T.id[x]):T.fd(x);
int fy=T.id[y]?T.fd(T.id[y]):T.fd(y);
if(fx==fy){
ans[u]=-1;
}
else{
ans[u]=-2;
}
}
}
else if(e[u].op==5){
if(T.id[e[u].x]==-1){
ans[u]=0;
}
else{
int x=T.id[e[u].x]?T.fd(T.id[e[u].x]):T.fd(e[u].x);
ans[u]=T.sum[x];
}
}
int pos=top;
for(auto x: G[u]){
DFS(x);
T.revoke(pos);//回退
}
}
int main() {
int n, q; scanf("%d%d", &n ,&q);
for(int i=1; i<=n; i++){
T.a[i]=1;
}
for(int i=1; i<=q; i++){
ans[i]=-3;
G[i].clear();
}
T.init(n);
int op, k, x, y;
for(int i=1; i<=q; i++){
scanf("%d%d%d", &op, &k, &x);
if(op!=2&&op!=5){
scanf("%d", &y);
}
G[k].push_back(i);//时间树
e[i]={op, x, y};
}
DFS(0);
for(int i=1; i<=q; i++){
if(ans[i]==-1){
printf("Yes\n");
}
if(ans[i]==-2){
printf("No\n");
}
if(ans[i]>=0){
printf("%d\n", ans[i]);
}
}
return 0;
}

京公网安备 11010502036488号