• noip模拟赛(一)宠物之战


    宠物之战

    (senso.pas/c/cpp)

    【问题描述】

           众所周知,moreD的宠物已经被moreD奴役得体无完肤。这只宠物实在忍无可忍,把自己每天走魔法树的经历告诉了自己的宠物。同时他还说明了自己爬树是多么地慢,以至于moreD每天都残酷地训练他爬树。

           幸运的是moreD的宠物的宠物不是moreD的宠物,moreD的宠物深知”宠物是用来宠的而不是用来奴役的”这一点,所以moreD的宠物对待自己的宠物很有爱。所以moreD的宠物与其宠物商量着要推翻moreD的暴政,方法是把moreD告上法庭,就以自己每天被迫爬树来做证据。

    由于魔法树是树,训练树当然也是树啦。

           moreD的训练有着GX的文化,每天moreD会把自己的宠物通灵到树的一个端点上,这个通灵点可能与之前的通灵点相同。然后moreD命令他的宠物从这个点开始走,让这只宠物随便访问自己该天之前没有访问过的节点,一直走到该天无路可走,训练才会结束,宠物才可以休息。

           moreD的宠物每天都会在这棵树上训练,幸运的是他每天走过的训练路径都不同,直到若干天后,所有可能的训练路径都被走遍了。

           你,作为moreD宠物的宠物,一只被moreD的宠物宠着的宠物,当然想帮moreD的宠物算出他总共走过的路径长度啦。

    【输入格式】

           第一行包含两个正整数N,M,表示树的点数与边数。

           接下来M行,每行三个正整数表示Li,bi,ci分别表示树上有一条长度为Li的连接bi,ci两个结点的边

    【输出格式】

           仅一行表示答案。

    【输入样例】

           54

           12 1

           13 1

           24 2

           25 2

    【输出样例】

           37

    【数据范围】

           对于30%的数据N≤300

           对于70%的数据N≤3,000

           对于100%的数据对于所有输入的整数均不大于100,000,输入的树保证连通,无重边,无自环

    【样例解释】

           可能的训练路径有(1-2-4),(1-2-5),(1-3),(2-4),(2-5),(2-1-3),(3-1-2-4),(3-1-2-5)

    (4-2-5),(4-2-1-3),(5-2-4),(5-2-1-3)

           长度依次为3,3,1,2,2,2,4,4,4,4,4,4。和为37.

    【题解】

    从样例模拟解释中寻找规律,发现树的每条边会累加多次,那么,只要求出每条边的累计贡献的规律即可解决题目。

    而,每条边的贡献=该边的左子树的叶节点数*右子树的节点数+该边的右子树的叶节点数*左子树的节点数。

    #include<stdio.h>
    #include<stdlib.h>
    #include<memory.h>
    using namespace std;
    typedef long long ll;
    inline int read()
    {
    	int x=0,c=getchar(),f=1;
    	while(c<48||c>57){if(c=='-')f=-1;c=getchar();}
    	while(c>47&&c<58)x=x*10+c-48,c=getchar();
    	return x*f;
    }
    static long long ans=0;
    int d[100001],f[100001],s[100001];
    int n,cnt,v[200001],first[200001],nxt[200001],dis[200001];
    void Link(int x,int y,int z)
    {
    	v[++cnt]=y;
    	nxt[cnt]=first[x];
    	first[x]=cnt;
    	dis[cnt]=z;
    }
    void dfs(int pa,int rt)
    {
    	if(d[rt]==1)f[rt]=1;
    	s[rt]=1;
    	for(int i=first[rt];i;i=nxt[i])
    		if(pa^v[i]){
    			dfs(rt,v[i]);
    			s[rt]+=s[v[i]];
    			f[rt]+=f[v[i]];
    		}
    }
    void solve(int pa,int rt)
    {
    	for(int i=first[rt];i;i=nxt[i])
    		if(pa^v[i]){
    			solve(rt,v[i]);
    			ans+=(ll)dis[i]*(s[1]-s[v[i]])*f[v[i]]+(ll)dis[i]*(f[1]-f[v[i]])*s[v[i]];
    		}
    }
    int main()
    {
    	int m;
    	freopen("senso.in","r",stdin);
    	freopen("senso.out","w",stdout);
    	n=read(),m=read();
    	memset(d,0,sizeof(d));
    	memset(f,0,sizeof(f));
    	memset(s,0,sizeof(s));
    	while(m--){
    		int z=read(),x=read(),y=read();
    		Link(x,y,z);
    		Link(y,x,z);
    		d[x]++,d[y]++;
    	}
    	dfs(0,1);
    	solve(0,1);
    	printf("%I64d
    ",ans);
    	fclose(stdin);
    	fclose(stdout);
    	return 0;
    }



  • 相关阅读:
    旋转数组的最小值
    用堆栈实现队列
    二叉树的重建
    从尾到头打印链表
    实现替换空格
    java获取在各种编码下中文及英文的字符个数
    java定义一个二维数组
    java计算某个坐标是否在范围内
    java调用百度地图API
    map在遍历数据的过程中删除数据不出错
  • 原文地址:https://www.cnblogs.com/keshuqi/p/5957692.html
Copyright © 2020-2023  润新知