zoukankan      html  css  js  c++  java
  • 2019ICPC徐州区域赛 Kill the tree

    https://nanti.jisuanke.com/t/42552

    以上是交题网站计蒜客

    本题要求找到所有子树的所有重心

    性质1 : 两棵树合并,新树的重心在两旧树重心连线上

    性质2  :子树的重心一定在重儿子上

    性质3  :树上所有点到重心的距离的和最小

     

    当siz[root] - siz[x] > siz[x] 时,x要往上爬  (某大佬的推理)

    这种写法是每次都得都往上爬

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<vector>
    
    using namespace std;
    const int maxn = 2e5 + 777;
    struct Node {
    	int to;
    	int next;
    }G[maxn * 2];
    int z = 0;
    int head[maxn];
    
    int add(int x, int y) {
    	G[++z].to = y;
    	G[z].next = head[x];
    	head[x] = z;
    	return 0;
    }
    int n;
    int dp[maxn];
    int fa[maxn], siz[maxn];
    int dep[maxn];
    vector<int>ans[maxn];
    
    int unin(int root, int x, int y) {
    	while (dep[x] > dep[root] && siz[root] - siz[x] > siz[x]) {//让x往上爬
    		x = fa[x];
    	}
    	while (dep[y] > dep[root] && siz[root] - siz[y] > siz[y]) {
    		y = fa[y];
    	}
    	if (dep[x] > dep[y]) dp[root] = x;
    	else dp[root] = y;
    	return 0;
    }
    int son[maxn];
    
    int dfs(int x, int f,int d) {
    	int s = 0;
    	siz[x] = 1;
    	dep[x] = d;
    	fa[x] = f;
    
    	for (int i = head[x]; i; i = G[i].next) {
    		int p = G[i].to;
    		if (p == f) continue;
    		dfs(p, x, d + 1);
    		siz[x] += siz[p];		//先把x和p合并起来
    		unin(x, dp[x], dp[p]);  //然后开始往上爬
    	}
    	return 0;
    }
    
    
    
    int main() {
    	int be, en;
    	scanf("%d", &n);
    	for (int i = 1; i < n; i++) {
    		scanf("%d%d", &be, &en);
    		add(be, en);
    		add(en, be);
    	}
    	for (int i = 1; i <= n; i++) dp[i] = i;
    	dfs(1, 0, 1);
    	for (int i = 1; i <= n; i++) {
    		int x = dp[i];
    		ans[i].push_back(x);
    		int t = fa[x];
    		if (t != 0 && siz[i] - siz[x] == siz[x]) {
    			ans[i].push_back(t);
    		}
    		sort(ans[i].begin(), ans[i].end());
    		
    		if (ans[i].size() == 1) {
    			printf("%d
    ", ans[i][0]);
    		}
    		else {
    			printf("%d %d
    ", ans[i][0], ans[i][1]);
    		}
    	}
    
    	
    	return 0;
    }
    

    这个是找到重儿子,从重儿向上爬,好理解一些,

    这个更快一些

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<vector>
    
    using namespace std;
    const int maxn = 2e5 + 777;
    struct Node {
    	int to;
    	int next;
    }G[maxn * 2];
    int z = 0;
    int head[maxn];
    
    int add(int x, int y) {
    	G[++z].to = y;
    	G[z].next = head[x];
    	head[x] = z;
    	return 0;
    }
    int n;
    int dp[maxn];
    int fa[maxn], siz[maxn];
    int dep[maxn];
    vector<int>ans[maxn];
    
    int unin(int root, int x, int y) {
    	while (dep[x] > dep[root] && siz[root] - siz[x] > siz[x]) {//让x往上爬
    		x = fa[x];
    	}
    	while (dep[y] > dep[root] && siz[root] - siz[y] > siz[y]) {
    		y = fa[y];
    	}
    	if (dep[x] > dep[y]) dp[root] = x;
    	else dp[root] = y;
    	return 0;
    }
    int son[maxn];
    
    int dfs(int x, int f,int d) {
    	int s = 0;
    	siz[x] = 1;
    	dep[x] = d;
    	fa[x] = f;
    
    	for (int i = head[x]; i; i = G[i].next) {
    		int p = G[i].to;
    		if (p == f) continue;
    		dfs(p, x, d + 1);
    		siz[x] += siz[p];		//先把x和p合并起来
    		if (s < siz[p]) {
    			s = siz[p];
    			son[x] = p;
    		}
    	}
    	dp[x] = x;
    	if (!son[x]) return 0;
    	int p = dp[son[x]];//重儿子的重心
    	while (dep[p] > dep[x] && siz[x] - siz[p] > siz[p]) {//满足条件就向上怕,最多能到根
    		p = fa[p];
    	}
    	dp[x] = p;
    	return 0;
    }
    
    
    int main() {
    	int be, en;
    	scanf("%d", &n);
    	for (int i = 1; i < n; i++) {
    		scanf("%d%d", &be, &en);
    		add(be, en);
    		add(en, be);
    	}
    	dfs(1, 0, 1);
    	for (int i = 1; i <= n; i++) {
    		int x = dp[i];
    		ans[i].push_back(x);
    		int t = fa[x];
    		if (t != 0 && siz[i] - siz[x] == siz[x]) {
    			ans[i].push_back(t);
    		}
    		sort(ans[i].begin(), ans[i].end());
    		
    		if (ans[i].size() == 1) {
    			printf("%d
    ", ans[i][0]);
    		}
    		else {
    			printf("%d %d
    ", ans[i][0], ans[i][1]);
    		}
    	}
    
    	
    	return 0;
    }
    
    寻找真正的热爱
  • 相关阅读:
    Nginx出现10055错误问题
    MVC报错的坑
    用Docker运行一个简单RazorDemo(一)
    dotnet run
    用Docker 在Centos7上部署Core2.1网站
    VS2015 自己用的插件
    帐户当前被锁定,所以用户 sa 登录失败。系统管理员无法将该帐户解锁
    加密方法汇总
    【备用】网页抓取、
    【转】项目奖金分配
  • 原文地址:https://www.cnblogs.com/lesning/p/12560509.html
Copyright © 2011-2022 走看看