可撤銷並查集用啟發式合並來優化。
用一個棧來記錄合並的操作,按照逆序恢復到原來的狀態。
記錄一個撤銷棧,元素為有序對 <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);
}
}