[Noip模拟题]宠物之战senso

Description

众所周知,moreD的宠物已经被moreD奴役得体无完肤。这只宠物实在忍无可忍,把自己每天走魔法树的经历告诉了
自己的宠物。同时他还说明了自己爬树是多么地慢,以至于moreD每天都残酷地训练他爬树。幸运的是moreD的宠物
的宠物不是moreD的宠物,moreD的宠物深知"宠物是用来宠的而不是用来奴役的"这一点,所以moreD的宠物对待自
己的宠物很有爱。所以moreD的宠物与其宠物商量着要推翻moreD的暴政,方法是把moreD告上法庭,就以自己每天
被迫爬树来做证据。由于魔法树是树,训练树当然也是树啦。moreD的训练有着GX的文化,每天moreD会把自己的宠
物通灵到树的一个端点上,这个通灵点可能与之前的通灵点相同。然后moreD命令他的宠物从这个点开始走,让这
只宠物随便访问自己该天之前没有访问过的节点,一直走到该天无路可走,训练才会结束,宠物才可以休息。more
D的宠物每天都会在这棵树上训练,幸运的是他每天走过的训练路径都不同,直到若干天后,所有可能的训练路径
都被走遍了。你,作为moreD宠物的宠物,一只被moreD的宠物宠着的宠物,当然想帮moreD的宠物算出他总共走过
的路径长度啦。

Input

第一行包含两个正整数N,M,表示树的点数与边数。接下来M行,每行三个正整数表示
Li,bi,ci分别表示树上有一条长度为Li的连接bi,ci两个结点的边。所有输入的整数均不大于100,000,输入的树保
证连通,无重边,无自环。

Output

仅一行表示答案。

Solution:

本题让我们求树上每一个点到所有叶子节点的长度总和,那么我们可以考虑每一条边对答案的贡献

一条边可以把树分成两个部分,而这条边被经过的次数则可以根据两部分的size和叶子节点个数得出

我们设sz[x]代表以x为根的子树的大小,num[x]代表以x为根节点的子树的叶子节点的个数

则一条边的贡献可表示为:\(val*(sz[rt]-sz[v])*num[v]+val*(num[rt]-num[v])*sz[v]\)

最后对每一条边都统计答案就行了。

注意本题输入形式!!!

Code:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1e5+1;
long long ans;
int rt,n,m,cnt,head[N],num[N],sz[N];
struct Edge{int nxt,to,val;}edge[N<<1];
void ins(int x,int y,int z){
	edge[++cnt].nxt=head[x];
	edge[cnt].to=y;edge[cnt].val=z;
	head[x]=cnt;
}
void dfs(int x,int fa){
	sz[x]=1;int flag=1;
	for(int i=head[x];i;i=edge[i].nxt){
		int y=edge[i].to;
		if(y==fa) continue;
		dfs(y,x);flag=0;
		sz[x]+=sz[y];num[x]+=num[y];
	}num[x]+=flag;
}
void calc(int x,int fa){
	for(int i=head[x];i;i=edge[i].nxt){
		int y=edge[i].to,z=edge[i].val;
		if(y==fa) continue;calc(y,x);
		int u1=num[1]-num[y],u2=sz[1]-sz[y];
		ans+=u1*1ll*sz[y]*z;ans+=z*1ll*u2*num[y];
	}
}
int read(){
	int x=0,f=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();}
	while(isdigit(ch)){x=x*10+ch-48;ch=getchar();}
	return x*f;
}
signed main(){
	n=read(),m=read();
	for(int i=1;i<=m;i++){
		int z=read(),x=read(),y=read();
		ins(x,y,z),ins(y,x,z);
	}dfs(1,0);calc(1,0);
	printf("%lld\n",ans);
	return 0;
}
posted @ 2019-07-01 15:15  DQY_dqy  阅读(214)  评论(0编辑  收藏  举报