版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
开始时有n个点形成的森林,共m个操作。
tp=1时,接下来一个参数u,表示将u所在的树树根变为u。
tp=2时,接下来一个参数u,询问以u为根的子树的大小。
tp=3时,接下来两个参数u,v,添加一条边(u,v),并将u所在树的根作为两棵树合并后的根。
...........................
第一行两个整数n,m。
接下来m行,每行开头是一个整数tp。tp=1或tp=2时,接下来一个整数u。tp=3时,接下来两个整数(u,v)。
............................
对于每个询问,你需要输出以u为根的子树大小。
记录siz[i]记录以i为根的子树的大小
连边时u,v,如果u树比v大,v作为子树的根重新计算siz,同时更新u到根的siz,u树比v小类似,小树的点最多重算log次所以叫启发式合并,但大树的点虽然只是u到根的链,不保证复杂度,随机数据比较好
根和原来的树不一样,判断一下位置
#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;
void read(int &x) {
char c;bool flag = 0;
while((c=getchar())<'0'||c>'9') flag |= (c=='-');
x=c-'0';while((c=getchar())>='0'&&c<='9') x = (x<<3)+(x<<1)+c-'0';
flag?x=-x:x;
}
#define N 210000
struct E {int to,next;}g[N*2];
int fr[N],tot;
void Add(int from,int to) {
g[++tot].to = to;
g[tot].next = fr[from];
fr[from] = tot;
}
int siz[N],rt[N],f[N],dep[N],fa[N],n,m;
int fd(int x) {
return x==f[x] ? x : f[x]=fd(f[x]);
}
void dfs(int t) {
siz[t] = 1;
for (int i = fr[t]; i; i = g[i].next) {
int to = g[i].to;
if(to == fa[t]) continue;
fa[to] = t; dep[to] = dep[t]+1;
dfs(to);
siz[t] += siz[to];
}
}
/*
void Link(int u,int v) {
Add(u,v); Add(v,u);
rt[fd(v)] = rt[fd(u)];
f[fd(v)] = fd(u);
dfs(fd(u));
}
*/
void Link(int u,int v) {
Add(u,v); Add(v,u);
int fu = fd(u),fv = fd(v),trt = rt[fu];
if(siz[fu] < siz[fv]) swap(u,v),swap(fu,fv); // v -> u
rt[f[fv] = fu] = trt;
fa[v] = u; dep[v] = dep[u]+1; dfs(v);
while(u) siz[u] += siz[v],u = fa[u];
}
int Query(int t) {
//cout<<siz[fd(t)]<<" ";
int r = rt[fd(t)];
if(t == r) return siz[fd(t)]; // BUG !!!!1
while(dep[fa[r]] > dep[t]) r = fa[r];
return fa[r]==t ? siz[fd(t)]-siz[r] : siz[t];
}
int main() {
freopen("dynamic_tree.in","r",stdin);freopen("dynamic_tree.out","w",stdout);
read(n); read(m);
for (int i = 1; i <= n; i++) {
rt[i] = i; f[i] = i; fa[i] = 0;
dep[i] = siz[i] = 1;
}
for (int i = 1,tp,u,v; i <= m; i++) {
read(tp); read(u);
if(tp == 1) rt[fd(u)] = u;
else if(tp == 2) printf("%d\n",Query(u));
else {
read(v);
Link(u,v);
}
// for(int j = 1;j <= n;j++) cout<<fa[j]<<" ";puts("");
// for(int j = 1; j <= n; j++) cout<<siz[j]<<" "; puts("\n");
}
return 0;
}