1. 程式人生 > >[JZOJ5776]【NOIP2008模擬】小x遊世界樹

[JZOJ5776]【NOIP2008模擬】小x遊世界樹

+= 不一定 truct 一行 自己 平臺 更新 return print

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的能量值。
很明顯以第一個點為根是最優的。


考慮不換根怎麽做, 那麽每條邊經過的次數就是它的子樹大小。

如果換根, 那麽考慮root的兒子x, 它的答案中只有root到x的邊的貢獻發生變化了。

發生的變化是減去root到x的貢獻, 加上x到root的貢獻。

於是求出root為1的答案, 然後再換根, 這樣統計答案是O(1)的, 總共是O(N)的。

註意更新的順序一定要按照dfs順序, 還要開Long long.


#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <map>
#define int long long
using namespace std;
inline int read() {
    int res=0;char c=getchar();bool f=0;
    while(!isdigit(c)) {if(c==-)f=1;c=getchar();}
    while(isdigit(c))res=(res<<3)+(res<<1)+(c^48),c=getchar();
    return f?-res:res;
}

#define reg register
#define N 700005

int n;
struct edge {
    int nxt, to, val;
}ed[N*2];
int head[N], cnt;
int ine[N];

inline void add(int x, int y, int z)
{
    ed[++cnt] = (edge){head[x], y, z};
    head[x] = cnt;
}

int a[N], siz[N], fat[N];
int ans, root = 1, res;
int f[N];

void dfs(int x, int fa)
{
    siz[x] = 1;
    for (reg int i = head[x] ; i ; i = ed[i].nxt)
    {
        int to = ed[i].to;
        if (to == fa) continue;
        fat[to] = x;
        ine[to] = i;
        dfs(to, x);
        siz[x] += siz[to];
    }
}

int efs(int x, int fa, int in)
{
    int sum = 0;
    for (reg int i = head[x] ; i ; i = ed[i].nxt)
    {
        int to = ed[i].to;
        if (to == fa) continue;
        sum += efs(to, x, i);
    }
    sum += siz[x] * (ed[in].val - a[fa]);
    return sum;
}

void ffs(int x, int fa, int in)
{
    if (x != 1) f[x] = f[fa] - (siz[x] * (ed[in].val - a[fa])) + (n - siz[x]) * (ed[in].val - a[x]);
    for (reg int i = head[x] ; i ; i = ed[i].nxt)
    {
        int to = ed[i].to;
        if (to == fa) continue;
        ffs(to, x, i);
    }
}

signed main()
{
    freopen("yggdrasil.in", "r", stdin);
    freopen("yggdrasil.out", "w", stdout);
    n = read();
    for (reg int i = 1 ; i <= n ; i ++) a[i] = read();
    for (reg int i = 1 ; i < n ; i ++)
    {
        int x = read(), y = read(), z = read();
        add(x, y, z);add(y, x, z);
    }
    dfs(1, 0);
    res = efs(1, 0, 0);
    ans = res;
    f[1] = ans;
    ffs(1, 0, 0);
    for (reg int i = 2 ; i <= n ; i ++) 
        if (f[i] < ans) {ans = f[i], root = i;}
    printf("%lld\n%lld\n", root, ans);
    return 0;
} 

[JZOJ5776]【NOIP2008模擬】小x遊世界樹