JZOJ5776 小x游世界树
Posted tokisaki-kurumi
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JZOJ5776 小x游世界树相关的知识,希望对你有一定的参考价值。
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分别表示这条无向边的起点,终点与耗费的能量值
第二行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。
数据保证一个点的加速器性能绝对小于等于它的所有的边所耗费的能量,保证所有节点都可以到达,保证没有数据与样例相同。
对于40%的数据:n<=1000
对于60%的数据:n<=8000
对于80%的数据:n<=100000
对于100%的数据:0<n<=700000;ai<=1000;1<=bi,ci<=n;di<=1000。
数据保证一个点的加速器性能绝对小于等于它的所有的边所耗费的能量,保证所有节点都可以到达,保证没有数据与样例相同。
Solution
首先暴力算出一个以某个节点为根所需的能量,然后从这个点在dfs一次,推导出以其他n个点为根所需能量。
1 #include <cstdio> 2 using namespace std; 3 struct arr 4 { 5 int x,y,next; 6 long long w; 7 }; 8 arr edge[2000000]; 9 int ls[1000000],n,p[1000000],son[1000000],e; 10 long long s[1000000],minn; 11 bool f[1000000]; 12 int dfs(int x) 13 { 14 int i=ls[x]; 15 son[x]=1; 16 while (i!=0) 17 { 18 if (f[edge[i].y]) 19 { 20 f[edge[i].y]=false; 21 dfs(edge[i].y); 22 son[x]=son[x]+son[edge[i].y]; 23 s[x]=s[x]+s[edge[i].y]+(edge[i].w-p[x])*(son[edge[i].y]); 24 } 25 i=edge[i].next; 26 } 27 } 28 int bdfs(int x) 29 { 30 int i=ls[x]; 31 while (i!=0) 32 { 33 if (f[edge[i].y]) 34 { 35 int k=edge[i].y; 36 s[k]=s[x]-(edge[i].w-p[x])*(son[k]); 37 s[k]=s[k]+(edge[i].w-p[k])*(n-son[k]); 38 if (s[k]<minn||s[k]==minn&&k<e) 39 { 40 minn=s[k]; 41 e=k; 42 } 43 f[k]=false; 44 bdfs(k); 45 } 46 i=edge[i].next; 47 } 48 } 49 int main() 50 { 51 scanf("%d",&n); 52 for (int i=1;i<=n;i++) 53 scanf("%d",&p[i]); 54 for (int i=1;i<=n-1;i++) 55 { 56 scanf("%d%d%d",&edge[i*2-1].x,&edge[i*2-1].y,&edge[i*2-1].w); 57 edge[i*2-1].next=ls[edge[i*2-1].x]; 58 ls[edge[i*2-1].x]=i*2-1; 59 edge[i*2].x=edge[i*2-1].y; 60 edge[i*2].y=edge[i*2-1].x; 61 edge[i*2].w=edge[i*2-1].w; 62 edge[i*2].next=ls[edge[i*2].x]; 63 ls[edge[i*2].x]=i*2; 64 } 65 for (int i=1;i<=n;i++) 66 f[i]=true; 67 f[1]=false; 68 dfs(1); 69 for (int i=1;i<=n;i++) 70 f[i]=true; 71 f[1]=false; 72 minn=s[1]; 73 e=1; 74 bdfs(1); 75 printf("%d ",e); 76 printf("%lld ",minn); 77 }
以上是关于JZOJ5776 小x游世界树的主要内容,如果未能解决你的问题,请参考以下文章