• [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
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    Java并发之CAS与AQS简介
    关系型数据库三范式
    分库分表使用场景及设计方式
    项目部署到tomcat出错(tomcat运行时的JDK版本)
    手写一个简化版Tomcat
    java并发之并发工具
    java并发之停止线程
    class中static总结-静态成员函数和静态成员变量
    45 孩子们的游戏(圆圈中最后剩下的数) + list操作总结+ for_each多记忆容易忘记
    C++ split分割字符串函数
  • 原文地址:https://www.cnblogs.com/NLDQY/p/11114210.html
Copyright © 2020-2023  润新知