zoukankan      html  css  js  c++  java
  • HIHO 16 C

    树分治。对于一棵子树的根节点,至少有一条边与儿子相连的属于重边。对于一条轻边,它的贡献值是两端子树大小的乘积,所以,重边应该是贡献值最大的一边。

    至于要求所有的点,进行深度优先搜索,因为移动一个点只会影响两个点的两个子树,这个可以维护。

    在进行DP时,选择计算最大的重边的值,答案就是用所有的边贡献值减去树的重边值的和。

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define LL long long
    using namespace std;
    
    const int MAX=100010;
    
    int head[MAX],tol;
    struct Edge{
    	int u,v,next;
    }edge[MAX*2];
    int n;
    
    void addedge(int u,int v){
    	edge[tol].u=u;
    	edge[tol].v=v;
    	edge[tol].next=head[u];
    	head[u]=tol++;
    }
    
    int counts[MAX]; LL dp[MAX];
    int weight1[MAX],weight2[MAX];
    LL ans[MAX],tot[MAX],par[MAX];
    
    void dfs(int u,int f){
    	counts[u]=1;
    	weight1[u]=weight2[u]=-1;
    	for(int e=head[u];e!=-1;e=edge[e].next){
    		int v=edge[e].v;
    		if(v!=f){
    			dfs(v,u);
    			counts[u]+=counts[v];
    			dp[u]+=dp[v];
    			if(weight1[u]==-1||(LL)(n-counts[v])*counts[v]>(LL)(n-counts[weight1[u]])*counts[weight1[u]]){
    				weight2[u]=weight1[u]; weight1[u]=v;
    			}
    			else if(weight2[u]==-1||(LL)(n-counts[v])*counts[v]>(LL)(n-counts[weight2[u]])*counts[weight2[u]]){
    				weight2[u]=v;
    			}
    	///		dp[u]+=(n-counts[v])*counts[v];
    		}
    	}
    	tot[u]=dp[u];
    	if(counts[u]>1){
    		dp[u]+=(LL)(n-counts[weight1[u]])*counts[weight1[u]];
    	}
    }
    
    void dfs_ans(int u,int f){
    	for(int e=head[u];e!=-1;e=edge[e].next){
    		int v=edge[e].v;
    		if(v==f) continue;
    		if(v==weight1[u]){
    			LL num=max((LL)(n-counts[u])*counts[u],(LL)(n-counts[weight2[u]])*counts[weight2[u]]);
    			par[v]=tot[u]-dp[v]+par[u]+num;
    		}
    		else{
    			LL num=max((LL)(n-counts[u])*counts[u],(LL)(n-counts[weight1[u]])*counts[weight1[u]]);
    			par[v]=tot[u]-dp[v]+par[u]+num;
    		}
    		dfs_ans(v,u);
    	}
    	LL num=max((LL)(n-counts[weight1[u]])*counts[weight1[u]],(LL)(n-counts[u])*counts[u]);
    	ans[u]=par[u]+tot[u]+num;
    }
    
    int main(){
    	while(scanf("%d",&n)!=EOF){
    		for(int i=1;i<=n;i++) head[i]=-1,counts[i]=0,dp[i]=0,par[i]=0;
    		tol=0;
    		int u,v;
    		for(int i=1;i<n;i++){
    			scanf("%d%d",&u,&v);
    			addedge(u,v);
    			addedge(v,u);
    		}
    		dfs(1,0);
    		dfs_ans(1,0);
    		LL ans_tot=0;
    		for(int i=1;i<=n;i++) ans_tot+=(LL)counts[i]*(n-counts[i]);
    		for(int i=1;i<=n;i++) cout<<ans_tot-ans[i]<<endl;
    	}
    	return 0;
    }
    

      

  • 相关阅读:
    (转) Linux中profile、bashrc、bash_profile之间的区别和联系
    Ubuntu 安装MyEclipse10
    VMware_ubuntu设置共享文件夹
    (转载)Android出现“Read-only file system”解决办法
    Android 执行 adb shell 命令
    android传感器使用
    Android源码下载和编译过程
    jquery实现的ajax
    转载SQL_trace 和10046使用
    查看Oracle相关日志 ADRCI
  • 原文地址:https://www.cnblogs.com/jie-dcai/p/4957756.html
Copyright © 2011-2022 走看看