• HDU6567 Cotree(树的重心/树形DP)


    Avin has two trees which are not connected. He asks you to add an edge between them to make them connected while minimizing the function (Sigma_{i = 1}^nSigma_{j = i + 1}^n dis(i, j)), where dis(i,j)represents the number of edges of the path from i to j. He is happy with only the function value.

    Input

    The first line contains a number n (2<=n<=100000). In each of the following n−2lines, there are two numbers u and v, meaning that there is an edge between u and v. The input is guaranteed to contain exactly two trees.

    Output

    Just print the minimum function value.

    Sample Input

    3
    1 2
    

    Sample Output

    4
    

    首先dfs求连通块确定出这些点分属于哪棵树,然后两次dfs求出来两棵树的重心(求中心大概也是可的),把重心连起来就得到了最后的树。剩下要做的就是统计任意两点之间的距离和。直接遍历点显然会T(也会有重复),不妨统计边的贡献,再开一个sz数组计算新树的各个子树的size,再来一次dfs直接计算累加答案即可。

    #include <bits/stdc++.h>
    #define N 200005
    using namespace std;
    int n, m, tot = 0, head[N], ver[2 * N], Next[2 * N];
    bool belong[N];//表示i这个点属于哪棵树 默认初始化为0
    int tree_size[2] = { 0 };
    //求树的重心
    int size[N],  // 这个节点的“大小”(所有子树上节点数 + 该节点)
        weight[N],  // 这个节点的“重量”
        centroid[2];   // 用于记录树的重心(存的是节点编号)
    int minn;
    void add(int x, int y) {
    	ver[++tot] = y, Next[tot] = head[x], head[x] = tot;
    }
    void getBelong(int x, int pre) {
    	belong[x] = 1;//
    	tree_size[1]++;
    	for(int i = head[x]; i; i = Next[i]) {
    		int y = ver[i];
    		if(y == pre || belong[y]) continue;
    		getBelong(y, x);
    	}
    }
    void GetCentroid(int x, int pre) {
    	size[x] = 1;
    	weight[x] = 0;
    	for(int i = head[x]; i; i = Next[i]) {
    		int y = ver[i];
    		if(y == pre) continue;
    		GetCentroid(y, x);
    		size[x] += size[y];
    		//weight[x] = max(weight[x], weight[y]);
    		weight[x] = max(weight[x], size[y]);
    	}
    	weight[x] = max(weight[x], tree_size[belong[x]] - size[x]);//注意这里不要误写成n - size[x]
    	if(weight[x] <= minn) {
    		minn = weight[x];
    		centroid[belong[x]] = x;
    	}
    }
    long long ans = 0;
    int sz[N];
    void calc(int x, int pre) {
    	sz[x] = 1;
    	for(int i = head[x]; i; i = Next[i]) {
    		int y = ver[i];
    		if(y == pre) continue;
    		calc(y, x);
    		ans += 1ll * sz[y] * (n - sz[y]);//计算贡献
    		sz[x] += sz[y];
    	}
    }
    int main() {
    	cin >> n;
    	memset(belong, 0, sizeof(belong));
    	for(int i = 1; i <= n - 2; i++) {
    		int u, v;
    		cin >> u >> v;
    		add(u, v);
    		add(v, u);
    	}
    	getBelong(1, 0);//把和第一个点联通的设置为1 其他的自然为0
    	tree_size[0] = n - tree_size[1];
    	minn = 0x3f3f3f3f;
    	GetCentroid(1, -1);
    	minn = 0x3f3f3f3f;
    	for(int i = 1; i <= n; i++) {
    		if(belong[i] != belong[1]) {
    			GetCentroid(i, -1);
    			break;
    		}
    	}
    	add(centroid[0], centroid[1]);
    	add(centroid[1], centroid[0]);
    	//cout << centroid[1] << ' ' << centroid[0] << endl;
    	//剩下的就是求树上点两两之间的距离和了
    	calc(1, 0);
    	cout << ans << endl;
    	return 0;
    }
    
  • 相关阅读:
    Qt之界面数据存储与获取(使用setUserData()和userData())
    UML中关联(Association)、聚合(Aggregation)和合成(Composition)之间的区别
    Entity Framework Model First下改变数据库脚本的生成方式
    keepalive学习
    函数、极限、连续
    C#集合基础与运用
    面向查询服务的参数化查询
    WinDbg 命令手册
    知识管理方法论
    项目管理Project
  • 原文地址:https://www.cnblogs.com/lipoicyclic/p/14692051.html
Copyright © 2020-2023  润新知