Newcoder 144 G.Pikachu(最大流+树形DP+高精度)

58 篇文章 1 订阅
44 篇文章 0 订阅

Description

给出一棵 n n n个节点的树,边有边权,对这 n n n个节点建一张完全图,图中两点间距离为两点的树上距离,问任意两点在图上的最大流之和

Input

第一行一整数 T T T表示用例组数,每组用例首先输入一整数 n n n表示点数,之后 n − 1 n-1 n1行每行输入三个整数 u , v , w u,v,w u,v,w表示 u , v u,v u,v之间有一条权值为 w w w的树边

( 1 ≤ T ≤ 10 , 2 ≤ n ≤ 1 0 5 , 1 ≤ w i ≤ 1000 ) (1\le T\le 10,2\le n\le 10^5,1\le w_i\le 1000) (1T10,2n105,1wi1000)

Output

输出任意两点在图上的最大流之和

Sample Input

2
3
1 2 1
2 3 1
5
1 2 1
2 3 1
2 4 1
4 5 2

Sample Output

Case #1: 7
Case #2: 72

Solution

s , t s,t s,t两点之间的最大流即为求两点的最小割,进而是将 n n n个点分成两个点集 S , T S,T S,T,使得 s ∈ S , t ∈ T s\in S,t\in T sS,tT,且 ∑ u ∈ S , v ∈ T d i s ( u , v ) \sum\limits_{u\in S,v\in T}dis(u,v) uS,vTdis(u,v)最小,以黑白染色来确定每点所属集合,为使两个集合之间的距离和最小,集合内的距离和应尽可能大,故除 s , t s,t s,t外其余点应同色,故 s , t s,t s,t之间最大流即为 m i n ( ∑ d i s ( u , i ) , ∑ d i s ( v , i ) ) min(\sum dis(u,i),\sum dis(v,i)) min(dis(u,i),dis(v,i)),只要求出一点到其余所有点的距离和即可

第一遍树形 D P DP DP求出所有点到根节点的距离和,第二遍树形 D P DP DP d p [ u ] dp[u] dp[u]表示所有点到 u u u点距离和,假设根节点为 1 1 1,那么 d p [ 1 ] dp[1] dp[1]在第一遍时已经求出,进而对于当前点 v v v,其父亲 u u u d p dp dp值已经确定,所有点中位于 v v v子树的点到达 u u u比到达 v v v多走了 w w w w w w u , v u,v u,v之间边权),其余点到达 u u u比到达 v v v少走了 w w w,故有转移

d p [ v ] = d p [ u ] + ( n − 2 ⋅ s i z e ( v ) ) ⋅ w dp[v]=dp[u]+(n-2\cdot size(v))\cdot w dp[v]=dp[u]+(n2size(v))w

Code

#include<cstdio>
#include<algorithm>
#include<vector>
#include<cstring>
using namespace std;
typedef long long ll;
typedef pair<int,int>P;
#define maxn 100005
struct BigInt
{
	const static int mod=10000;
	const static int LEN=4;
	int a[10],len;
	BigInt() 
	{
		memset(a,0,sizeof(a));
		len=1;
	}
	void init(ll x)
	{
		memset(a,0,sizeof(a));
		len=0;
		do
		{
			a[len++]=x%mod;
			x/=mod;
		}while(x);
	}
	void Init(const char s[])
	{
		memset(a,0,sizeof(a));
		int l=strlen(s),res=0;
		len=l/LEN;
		if(l%LEN)len++;
		for(int i=l-1;i>=0;i-=LEN)
		{
			int t=0,k=max(i-LEN+1,0);
			for(int j=k;j<=i;j++)t=t*10+s[j]-'0';
			a[res++]=t;
		}
	}
	int Compare(const BigInt &b)
	{
		if(len<b.len)return -1;
		if(len>b.len)return 1;
		for(int i=len-1;i>=0;i--)
			if(a[i]<b.a[i])return -1;
			else if(a[i]>b.a[i])return 1;
		return 0;
	}
	BigInt operator +(const BigInt &b)const
	{
		BigInt ans;
		ans.len=max(len,b.len);
		for(int i=0;i<=ans.len;i++)ans.a[i]=0;
		for(int i=0;i<ans.len;i++)
		{
			ans.a[i]+=((i<len)?a[i]:0)+((i<b.len)?b.a[i]:0);
			ans.a[i+1]+=ans.a[i]/mod;
			ans.a[i]%=mod;
		}
		if(ans.a[ans.len]>0)ans.len++;
		return ans;
	}
	BigInt operator -(const BigInt &b)const
	{
		BigInt ans;
		ans.len=len;
		int k=0;
		for(int i=0;i<ans.len;i++)
		{
			ans.a[i]=a[i]+k-b.a[i];
			if(ans.a[i]<0)ans.a[i]+=mod,k=-1;
			else k=0;			
		}
		while(ans.a[ans.len-1]==0&&ans.len>1)ans.len--;
		return ans;
	}
	BigInt operator *(const BigInt &b)const
	{
		BigInt ans;
		for(int i=0;i<len;i++)
		{
			int k=0;
			for(int j=0;j<b.len;j++)
			{
				int temp=a[i]*b.a[j]+ans.a[i+j]+k;
				ans.a[i+j]=temp%mod;
				k=temp/mod;
			}
			if(k!=0)ans.a[i+b.len]=k;
		}
		ans.len=len+b.len;
		while(ans.a[ans.len-1]==0&&ans.len>1)ans.len--;
		return ans;
	}
	BigInt operator /(const int &n)const
	{
		BigInt ans;
		ans.len=len;
		int k=0;
		for(int i=ans.len-1;i>=0;i--)
		{
			k=k*mod+a[i];
			ans.a[i]=k/n;
			k=k%n;
		}
		while(ans.a[ans.len-1]==0&&ans.len>1)ans.len--;
		return ans;
	}
	void output()
	{
		printf("%d",a[len-1]);
		for(int i=len-2;i>=0;i--)
			printf("%04d",a[i]);
		printf("\n");
	}
};
vector<P>e[maxn];
int T,Case=1,n,Size[maxn];
ll f[maxn],g[maxn];
void dfs1(int u,int fa)
{
	Size[u]=1;
	f[u]=0;
	for(int i=0;i<e[u].size();i++)
	{
		int v=e[u][i].first,w=e[u][i].second;
		if(v==fa)continue;
		dfs1(v,u);
		Size[u]+=Size[v];
		f[u]+=f[v]+(ll)w*Size[v];
	}
}
void dfs2(int u,int fa)
{
	for(int i=0;i<e[u].size();i++)
	{
		int v=e[u][i].first,w=e[u][i].second;
		if(v==fa)continue;
		g[v]=g[u]+(ll)w*(n-2*Size[v]);
		dfs2(v,u);
	}
}
int main()
{
	scanf("%d",&T);
	while(T--)
	{
		scanf("%d",&n);
		for(int i=1;i<=n;i++)e[i].clear();
		for(int i=1;i<n;i++)
		{
			int a,b,c;
			scanf("%d%d%d",&a,&b,&c);
			e[a].push_back(P(b,c));
			e[b].push_back(P(a,c));
		}
		dfs1(1,0);
		g[1]=f[1];
		dfs2(1,0);
		sort(g+1,g+n+1);
		BigInt ans,a,b;
		ans.init(0);
		for(int i=1;i<n;i++)
		{
			a.init(g[i]);
			b.init(n-i);
			ans=ans+a*b;
		}
		printf("Case #%d: ",Case++);
		ans.output();
	}
	return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值