zoukankan      html  css  js  c++  java
  • [jzoj 5776]【NOIP2008模拟】小x游世界树 (树形dp)

    传送门

    Description

    小x得到了一个(不可靠的)小道消息,传说中的神岛阿瓦隆在格陵兰海的某处,据说那里埋藏着亚瑟王的宝藏,这引起了小x的好奇,但当他想前往阿瓦隆时发现那里只有圣诞节时才能到达,然而现在已经春天了,不甘心的他将自己的目的地改成了世界树,他耗费了大量的时间,终于将自己传送到了世界树下。世界树是一棵非常巨大的树,它有着许许多多的枝条以及节点,每个节点上都有一个平台。好不容易来到传说中的世界树下,小x当然要爬上去看看风景。小x每经过一条边都会耗费体力值。然而世界树之主想给他弄(gáo)些(dǐan)麻(shì)烦(qíng),于是他在每条边上都设了一个魔法阵,当小x踏上那条边时会被传送回根节点,魔法阵只生效一次。这岂不是要累死小x?幸运的是,每个平台上都有无数个加速器,这些加速器可以让小x在当前节点所连的边上耗费的体力值减少,不同平台的加速器性能不一定相同,但同一个平台的加速器性能绝对相同。世界树之主给了小x一次“换根”的机会,他可以将世界树的任何一个节点变为根,但所有的边都不能改变。小x想问你,将根换为哪个节点能使小x爬到世界树上的每个节点耗费的体力值和最少。默认编号为1的点为初始根。

    Input

    第一行一个数n,表示有n个节点。
    第二行n个数ai,表示每个平台上的加速器的性能。
    第三至n+1行,每行三个数bi,ci,di分别表示这条无向边的起点,终点与耗费的能量值

    Output

    第一行一个数,表示要换成的节点,如果有多个点为根时耗费的体力值都最小,则输出编号最小的那个。如果保持为1是最优的,就输出1。
    第二行一个数,表示最小耗费的体力值。

    Sample Input

    4
    2 1 3 3
    1 2 3
    1 3 4
    2 4 6

    Sample Output

    1
    9

    Data Constraint

    对于20%的数据:n<=100
    对于40%的数据:n<=1000
    对于60%的数据:n<=8000
    对于80%的数据:n<=100000
    对于100%的数据:0<n<=700000;ai<=1000;1<=bi,ci<=n;di<=1000。
    数据保证一个点的加速器性能绝对小于等于它的所有的边所耗费的能量,保证所有节点都可以到达,保证没有数据与样例相同。

    Hint

    提示:
    样例解释:
    如果以第一个点为根,则需要耗费0(到1)+1(到2)+2(到3)+6(到4)=9的能量值。
    如果以第二个点为根,则需要耗费2(到1)+0(到2)+4(到3)+5(到4)=11的能量值。
    如果以第三个点为根,则需要耗费1(到1)+2(到2)+0(到3)+7(到4)=10的能量值。
    如果以第四个点为根,则需要耗费5(到1)+3(到2)+7(到3)+0(到4)=15的能量值。
    很明显以第一个点为根是最优的。

    Solution

    考虑先以1为根节点求出答案
    然后往子节点转移

    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define F(i,a,b) for(register int i=(a);i<=(b);i++)
    #define E(i,u) for(register int i=head[u];i;i=nxt[i])
    #define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<20,stdin)),p1==p2?EOF:*p1++)
    using namespace std;
    typedef long long LL;
    
    char buf[1<<20],*p1,*p2;
    inline int read() {
    	int x=0,f=1; char c=getchar();
    	while(!isdigit(c)) {if(c=='-')f=-f;c=getchar();}
    	while(isdigit(c)) x=(x<<1)+(x<<3)+c-48,c=getchar();
    	return x*f;
    }
    
    const int N=700010;
    int n,cnt,root;
    int da[N],nxt[N<<1],to[N<<1],cost[N<<1],head[N],siz[N];
    LL sum,ans;
    LL f[N];
    
    void dfs1(int u,int pre) {
    	siz[u]=1;
    	E(i,u) {
    		int v=to[i];if(v==pre) continue;
    		dfs1(v,u);
    		siz[u]+=siz[v];
    		f[1]+=(LL)max((LL)cost[i]-da[u],0ll)*(LL)siz[v];//1
    	}
    }
    
    void dfs2(int u,int pre) {
    	E(i,u) {
    		int v=to[i];if(v==pre) continue;
    		f[v]=f[u]-(cost[i]-da[u])*siz[v]+(cost[i]-da[v])*(n-siz[v]);
    		if(f[v]<=f[root]) root=f[v]<f[root]?v:min(root,v);
    		dfs2(v,u);
    	}
    }
    
    #define add(a,b,c) nxt[++cnt]=head[a],to[cnt]=b,cost[cnt]=c,head[a]=cnt
    int main() {
    	freopen("yggdrasil.in","r",stdin);
    	freopen("yggdrasil.out","w",stdout);
    	n=read();
    	F(i,1,n) da[i]=read();
    	F(i,1,n-1) {
    		int u=read(),v=read(),w=read();
    		add(u,v,w);add(v,u,w);
    	}
    	dfs1(1,0);
    	root=1;
    	dfs2(1,0);
    	printf("%d
    %lld",root,f[root]);
    	return 0;
    }
    
    版权声明:本文为博主原创文章,未经博主允许不得转载。 博主:https://www.cnblogs.com/Menteur-Hxy/
  • 相关阅读:
    接口类和抽象类
    生成器和迭代器
    装饰器
    KMP算法(java,c++)
    java EE
    XML
    SQL语法
    单元测试
    JDBC
    SpringCloud
  • 原文地址:https://www.cnblogs.com/Menteur-Hxy/p/9451851.html
Copyright © 2011-2022 走看看