1. 程式人生 > >不知哪個OJ 小x遊世界樹 換根?不知。

不知哪個OJ 小x遊世界樹 換根?不知。

sign [1] 數據 消息 code 字典序 wid ont 傳說

小x遊世界樹

(yggdrasi.pas/c/cpp)

【問題描述】

小x得到了一個(不可靠的)小道消息,傳說中的神島阿瓦隆在格陵蘭海的某處,據說那裏埋藏著亞瑟王的寶藏,這引起了小x的好奇,但當他想前往阿瓦隆時發現那裏只有聖誕節時才能到達,然而現在已經春天了,不甘心的他將自己的目的地改成了世界樹,他耗費了大量的時間,終於將自己傳送到了世界樹下。世界樹是一棵非常巨大的樹,它有著許許多多的枝條以及節點,每個節點上都有一個平臺。好不容易來到傳說中的世界樹下,小x當然要爬上去看看風景。小x每經過一條邊都會耗費體力值。然而世界樹之主想給他弄(gáo)些(dǐan)麻(shì)煩(qíng),

於是他在每條邊上都設了一個魔法陣,當小x踏上那條邊時會被傳送回根節點,魔法陣只生效一次。這豈不是要累死小x?

幸運的是,每個平臺上都有無數個加速器,這些加速器可以讓小x在當前節點所連的邊上耗費的體力值減少,不同平臺的加速器性能不一定相同,但同一個平臺的加速器性能絕對相同。

世界樹之主給了小x一次“換根”的機會,他可以將世界樹的任何一個節點變為根,但所有的邊都不能改變。小x想問你,將根換為哪個節點能使小x爬到世界樹上的每個節點耗費的體力值和最少。默認編號為1的點為初始根。

【輸入】

第一行一個數n,表示有n個節點。

第二行n個數ai,表示每個平臺上的加速器的性能。

第三至n+1行,每行三個數bi,ci,di分別表示這條無向邊的起點,終點與耗費的能量值

【輸出】

第一行一個數,表示要換成的節點,如果有多個點為根時耗費的體力值都最小,則輸出編號最小的那個。如果保持為1是最優的,就輸出1。

第二行一個數,表示最小耗費的體力值。

【輸入輸出樣例1】

4

2 1 3 3

1 2 3

1 3 4

2 4 6

1

9

【數據範圍】

對於20%的數據:n<=100

對於40%的數據:n<=1000

對於60%的數據:n<=8000

對於80%的數據:n<=100000

對於100%的數據:0<n<=700000;ai<=1000;1<=bi,ci<=n;di<=1000。

數據保證一個點的加速器性能絕對小於等於它的所有的邊所耗費的能量,保證所有節點都可以到達,保證沒有數據與樣例相同。

【樣例解釋】

如果以第一個點為根,則需要耗費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的能量值。

很明顯以第一個點為根是最優的。

好吧很明顯的樹上操作。。。考試是不知剛開始打了寫什麽辣雞玩意QWQ

先求出來以1(隨便哪個都行)為根的代價,具體地,把他當作根,做一遍dfs,每條邊的貢獻是(w(u,v)-a[u])*size[v];

然後主要就是在樹上如何轉移:由u到v時,當前的cost(cost初值是以1為根的代價)-= (w(u,v)-a[u])*size[v] 再+=(w(u,v)-a[v])*(sz[1]-sz[v]),相當於是原來是從u到v,現在是從v到u,回溯時反向操作。

然後更新答案時記得加上字典序的比較,否則會死(親身經歷QWQ)

#include<cstdio>
#include<iostream>
#define ll long long
#define R register ll
using namespace std;
const int N=700010;
inline int g() {
    R ret=0,fix=1; register char ch; while(!isdigit(ch=getchar())) fix=ch==-?-1:fix;
    do ret=ret*10+(ch^48); while(isdigit(ch=getchar())); return ret*fix;
}
int n,cnt,ccnt,anss;
int vr[N<<1],nxt[N<<1],w[N<<1],fir[N],sz[N],a[N];
ll cost,ans=1E+15;
inline void add(int u,int v,int ww) {vr[++cnt]=v,w[cnt]=ww,nxt[cnt]=fir[u],fir[u]=cnt;}
inline void dfsdown(int u,int fa) { sz[u]=1;
    for(R i=fir[u];i;i=nxt[i]) { R v=vr[i];
        if(v==fa) continue; 
        dfsdown(v,u); sz[u]+=sz[v]; cost+=(w[i]-a[u])*sz[v];
    } 
} 
inline void solve(int u,int fa) {
    if(ans>cost||(ans==cost&&anss>u)) anss=u,ans=cost;
    for(R i=fir[u];i;i=nxt[i]) { R v=vr[i];
        if(v==fa) continue;
        cost-=(w[i]-a[u])*sz[v],cost+=(w[i]-a[v])*(sz[1]-sz[v]); solve(v,u);
        cost+=(w[i]-a[u])*sz[v],cost-=(w[i]-a[v])*(sz[1]-sz[v]);
    }
}
signed main() { freopen("yggdrasil.in","r",stdin); freopen("out.out","w",stdout);
    n=g(); for(R i=1;i<=n;++i) a[i]=g(); 
    for(R i=1,u,v,w;i<n;++i)  u=g(),v=g(),w=g(),add(u,v,w),add(v,u,w);
    dfsdown(1,0); solve(1,0); printf("%d\n%lld\n",anss,ans);
} 

因為聽了BK老師的課而自閉了幾天。。。今天考試智商下降體現在下一題上。。。QWQ2019.05.04

不知哪個OJ 小x遊世界樹 換根?不知。