可撤销并查集用启发式合并来优化。
用一个栈来记录合并的操作,按照逆序恢复到原来的状态。
记录一个撤销栈,元素为有序对 <int* pElem,int nValue>
,如果撤销这个步骤则令 *pElem=nValue
即可。那么在启发式合并的时候,每次修改了什么就记录什么,撤销的时候删除即可。
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 1000005;
struct dsu
{
int fa[N],rank[N];
stack<pair<int*,int>> sta;
void init(int n)
{
for(int i=1;i<=n;i++)
{
fa[i]=i;
rank[i]=1;
}
}
int find(int p)
{
return fa[p]==p ? p : find(fa[p]);
}
void merge(int p,int q)
{
p=find(p);
q=find(q);
if(p!=q)
{
if(rank[p]>rank[q]) swap(p,q);
sta.push({fa+p,fa[p]});
fa[p]=q;
if(rank[p]==rank[q])
{
sta.push({rank+q,rank[q]});
++rank[q];
}
else
{
sta.push({NULL,0});
}
}
}
void _undo()
{
if(sta.size()==0) return;
if(sta.top().first!=NULL)
{
*sta.top().first=sta.top().second;
}
sta.pop();
}
void undo()
{
_undo();
_undo();
}
void print(int n)
{
cout<<" FA[] = ";
for(int i=1;i<=n;i++)
{
cout<<fa[i]<<" ";
}
cout<<endl;
}
} dsu;
signed main()
{
int n;
cin>>n;
dsu.init(n);
while(true)
{
string op;
int t1,t2;
cin>>op;
if(op=="merge")
{
cin>>t1>>t2;
dsu.merge(t1,t2);
}
if(op=="undo")
{
dsu.undo();
}
dsu.print(n);
}
}