[COGS2701]动态树 (启发式合并)

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/qq_33831360/article/details/102528300

开始时有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;
}

猜你喜欢

转载自blog.csdn.net/qq_33831360/article/details/102528300