1. 程式人生 > >[Bzoj3677][Apio2014]連珠線(樹形dp)

[Bzoj3677][Apio2014]連珠線(樹形dp)

print -i 定義 但是 bsp https 開始 sta http

3677: [Apio2014]連珠線


Time Limit: 10 Sec Memory Limit: 128 MB
Submit: 434 Solved: 270
[Submit][Status][Discuss]

Description


在列奧納多·達·芬奇時期,有一個流行的童年遊戲,叫做“連珠線”。不出所料,玩這個遊戲只需要珠子和線,珠子從1到禮編號,線分為紅色和藍色。遊戲
開始時,只有1個珠子,而接下來新的珠子只能通過線由以下兩種方式被加入:
1.Append(w,杪):-個新的珠子w和一個已有的珠子杪連接,連接使用紅線。

2.Insert(w,u,v):-個新的珠子w加入到一對通過紅線連接的珠子(u,杪)
之間,並將紅線改成藍線。也就是將原來u連到1的紅線變為u連到w的藍線與W連到V的藍線。
無論紅線還是藍線,每條線都有一個長度。而在遊戲的最後,將得到遊戲的
最後得分:所有藍線的長度總和。
現在有一個這個遊戲的最終結構:你將獲取到所有珠子之間的連接情況和所
有連線的長度,但是你並不知道每條線的顏色是什麽。
你現在需要找到這個結構下的最大得分,也就是說:你需要給每條線一個顏
色f紅色或藍色),使得這種連線的配色方案是可以通過上述提到的兩種連線方式
操作得到的,並且遊戲得分最大。在本題中你只需要輸出最大的得分即可。

Input


第一行是一個正整數n,表示珠子的個數,珠子編號為1剄n。
接下來n-l行,每行三個正整數ai,bi(l≤ai10000),表示有一條長度為ci的線連接了珠子ai和珠子bi。

Output


輸出一個整數,為遊戲的最大得分。

Sample Input


5
1 2 10
1 3 40
1 4 15
1 5 20

Sample Output


60 





HINT


數據範圍滿足1≤n≤200000。

分析:


一開始以為定義狀態f[i][0/1]表示第i個點是不是中心點亂樹形dp就可以了,結果考完只有10分

原因:這個題加入有順序,任何時刻加入的點都是一個聯通塊。 這樣我們就要枚舉根節點,並且合並只能合並 父-子-孫。 然後復雜度是O(n^2)的。 我們可以優化一下換根,不用每次換根都去枚舉,如果每次只枚舉當前根節點沒當過根的兒子,會重新dp的只有兩個點,換根復雜度O(1) 所以總復雜度O(n) 然後一開始用了vector啥的,bzoj上過了,cena上一首涼涼送給stl,被迫看了別人的代碼改出來QAQ

AC代碼:


# include <iostream>
# include <cstdio>                                                                                                                                                                                    
using namespace std;
const int N = 3e5 + 12;
const int inf = 0x3f3f3f3f;
int head[N],dt,n,ans,f1[N],f2[N],g[N];
struct Edge{
    int to,nex,w;
}edge[N << 1];
void AddEdge(int u,int v,int w)
{
    edge[++dt] = (Edge){v,head[u],w};
    head[u] = dt;
}
void dfs(int u,int pre)
{
    f1[u] = f2[u] = -inf;int t;
    for(int i = head[u];i;i = edge[i].nex)
    {
        if(edge[i].to == pre)continue;
        dfs(edge[i].to,u);
        t = g[edge[i].to] + edge[i].w - max(g[edge[i].to],g[edge[i].to] + f1[edge[i].to] + edge[i].w);
        if(t > f1[u])f2[u] = f1[u],f1[u] = t;
        else if(t > f2[u])f2[u] = t;
        g[u] += max(g[edge[i].to],g[edge[i].to] + f1[edge[i].to] + edge[i].w);
    }
}
void Dfs(int u,int pre)
{
    ans = max(ans,g[u]);int s,t,c;
    for(int i = head[u];i;i = edge[i].nex)
    {
        if(edge[i].to == pre)continue;
        s = g[u] - max(g[edge[i].to],g[edge[i].to] + f1[edge[i].to] + edge[i].w);
        t = g[edge[i].to] + edge[i].w - max(g[edge[i].to],g[edge[i].to] + f1[edge[i].to] + edge[i].w);
        if(f1[u] == t)c = f2[u];else c = f1[u];
        g[edge[i].to] += max(s,s + c + edge[i].w);
        t = s + edge[i].w - max(s,s + c + edge[i].w);
        if(t > f1[edge[i].to])f2[edge[i].to] = f1[edge[i].to],f1[edge[i].to] = t;
        else if(t > f2[edge[i].to])f2[edge[i].to] = t;
        Dfs(edge[i].to,u);
    }
}
int main()
{
    freopen("beads.in","r",stdin);
    freopen("beads.out","w",stdout);
    scanf("%d",&n);int x,y,z;
    for(int i = 1;i < n;i++)
    {
        scanf("%d %d %d",&x,&y,&z);
        AddEdge(x,y,z);AddEdge(y,x,z);
    }
    dfs(1,-1);Dfs(1,-1);
    printf("%d\n",ans);
    fclose(stdin);
    fclose(stdout);
    return 0;
}

[Bzoj3677][Apio2014]連珠線(樹形dp)