3743: [Coci2015]Kamp

3743: [Coci2015]Kamp

Time Limit: 10 Sec   Memory Limit: 128 MB
Submit: 442   Solved: 210
[ Submit][ Status][ Discuss]

Description

一颗树n个点,n-1条边,经过每条边都要花费一定的时间,任意两个点都是联通的。
有K个人(分布在K个不同的点)要集中到一个点举行聚会。
聚会结束后需要一辆车从举行聚会的这点出发,把这K个人分别送回去。
请你回答,对于i=1~n,如果在第i个点举行聚会,司机最少需要多少时间把K个人都送回家。

Input

第一行两个数,n,K。
接下来n-1行,每行三个数,x,y,z表示x到y之间有一条需要花费z时间的边。
接下来K行,每行一个数,表示K个人的分布。

Output

输出n个数,第i行的数表示:如果在第i个点举行聚会,司机需要的最少时间。

Sample Input

7 2
1 2 4
1 3 1
2 5 1
2 4 2
4 7 3
4 6 2
3
7

Sample Output

11
15
10
13
16
15
10

HINT

【数据规模】

K <= N <= 500000

1 <= x,y <= N, 1 <= z <= 1000000


Source

[ Submit][ Status][ Discuss]



随意选择一个起点,以它为根,司机的载人过程可以这样考虑

每次选择一个有关键点的子树,往那里走,把所有在里面的人送到家以后再回来

这样最后会回到根,每条需要经过的边恰好经过两次

不过并没有规定最后要回来,所以选择一条最长的路径,这条路径上的边只经过一次就行了

用树形dp维护一下,然后维护链长的最大值和次大值,方便换根的时候转移

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
 
const int maxn = 5E5 + 50;
typedef long long LL;
const LL INF = 1E16;
 
struct E{
    int to; LL w; E(){}
    E(int to,LL w): to(to),w(w){}
};
 
int n,k;
LL f[maxn],g[maxn],h[maxn],fr[maxn],sc[maxn],pos[maxn],siz[maxn];
 
vector  v[maxn];
 
void Dfs1(int x,int fa)
{
    fr[x] = sc[x] = -INF;
    if (siz[x] == 1) fr[x] = 0,pos[x] = -1;
    for (int i = 0; i < v[x].size(); i++)
    {
        E e = v[x][i]; if (e.to == fa) continue;
        Dfs1(e.to,x); f[x] += f[e.to]; siz[x] += siz[e.to];
        if (siz[e.to])
        {
            f[x] += 2LL * e.w;
            LL Fr = fr[e.to] != -INF ? e.w + fr[e.to] : -INF;
            LL Sc = sc[e.to] != -INF ? e.w + sc[e.to] : -INF;
            if (Fr <= fr[x]) sc[x] = max(sc[x],Fr);
            else pos[x] = i,sc[x] = fr[x],fr[x] = Fr;
        }
    }
}
 
void Dfs2(int x,int fa,LL sum,int tot,LL Max)
{
    h[x] = max(fr[x],Max); g[x] = sum + f[x];
    for (int i = 0; i < v[x].size(); i++)
    {
        E e = v[x][i];
        if (e.to == fa) continue;
        LL Nex,ma = -INF; int cnt;
        if (Max != -INF) ma = Max + e.w;
        if (pos[x] != i && fr[x] != -INF) ma = max(ma,fr[x] + e.w);
        else if (sc[x] != -INF) ma = max(ma,sc[x] + e.w);
        cnt = tot + siz[x] - siz[e.to];
        Nex = sum + f[x] - f[e.to];
        if (cnt && !siz[e.to]) Nex += 2LL * e.w;
        else if (!cnt && siz[e.to]) Nex -= 2LL * e.w;
        Dfs2(e.to,x,Nex,cnt,ma);
    }
}
 
int getint()
{
    char ch = getchar(); int ret = 0;
    while (ch < '0' || '9' < ch) ch = getchar();
    while ('0' <= ch && ch <= '9')
        ret = ret * 10 + ch - '0',ch = getchar();
    return ret;
}
 
char s[20];
void Print(LL x)
{
    if (!x) {puts("0"); return;} int len = 0;
    while (x) s[++len] = x % 10,x /= 10;
    for (int i = len; i; i--) putchar(s[i] + '0'); puts("");
}
 
int main()
{
    #ifdef DMC
        freopen("DMC.txt","r",stdin);
    #endif
     
    n = getint(); k = getint();
    if (!k)
    {
        for (int i = 1; i <= n; i++)
            puts("0"); return 0;
    }
    for (int i = 1; i < n; i++)
    {
        int x = getint(),y,w;
        y = getint(); w = getint();
        v[x].push_back(E(y,w));
        v[y].push_back(E(x,w));
    }
    for (int i = 1; i <= k; i++) siz[getint()] = 1;
    Dfs1(1,0); Dfs2(1,0,0,0,-INF);
    for (int i = 1; i <= n; i++) Print(g[i] - h[i]);
    return 0;
}

你可能感兴趣的:(dp,树)