[APIO2014]連珠線

3647 [APIO2014]連珠線

題目描述

在達芬奇時代,有一個流行的兒童遊戲稱爲連珠線。固然,這個遊戲是關於珠子和線的。線是紅色或藍色的,珠子被編號爲 1 到 n。這個遊戲從一個珠子開始,每次會用以下方式添加一個新的珠子:html

Append(w, v):一個新的珠子 $w$ 和一個已經添加的珠子 v 用紅線鏈接起來。ios

Insert(w, u, v):一個新的珠子$w$插入到用紅線連起來的兩個珠子$u,v$之間。具體過程是刪去 u,v 之間紅線,分別用藍線鏈接 u,w 和 w, vapp

每條線都有一個長度。遊戲結束後,你的最終得分爲藍線長度之和。spa

給你連珠線遊戲結束後的遊戲局面,只告訴了你珠子和鏈的鏈接方式以及每條線的長度,沒有告訴你每條線分別是什麼顏色。code

你須要寫一個程序來找出最大可能得分。即,在全部以給出的最終局面結束的連珠線遊戲中找出那個得分最大的,而後輸出最大可能得分。orm

輸入格式

第一行一個正整數 $n$,表示珠子的數量。珠子從 1 到 n 編號。htm

接下來 n - 1 行每行三個整數 $a_{i},b_{i},c_{i}$。保證 $1 \leqslant a_{i},b_{i} \leqslant n$,$1 \leqslant c_{i} \leqslant 10000$。表示 ai 號珠子和 bi 號珠子間連了長度爲 ci 的線。blog

輸出格式

輸出一個整數,表示最大可能得分。遊戲

輸入輸出樣例

輸入 #1
5
1 2 10
1 3 40
1 4 15
1 5 20
輸出 #1
60
輸入 #2
10
4 10 2
1 2 21
1 3 13
6 7 1
7 9 5
2 4 3
2 5 8
1 6 55
6 8 34
輸出 #2
140

說明/提示

【樣例描述1】input

能夠經過以下方式得到 60 分:首先從 3 號珠子開始。

5 和 3 連起來。(線長度任意)

在 3 和 5 之間插入 $11$。(線長分別爲 40 和 20)。

把 2 和 1 用長度爲 $10$ 的線連起來。

把 4 和 1 用長度爲 $15$ 的線連起來。

【限制與約定】

第一個子任務共 13 分,知足 $1\leqslant n \leqslant 10$

第二個子任務共 15 分,知足 $1\leqslant n \leqslant 200$

第三個子任務共 29 分,知足 $1\leqslant n \leqslant 10000$

第四個子任務共 43 分,知足 $1\leqslant n \leqslant 200000$

 

Solution:

爲了方便,咱們把每一個珠子當作一個節點

咱們很是開心的發現,結果確定是一棵邊顏色不一樣的樹

因爲剛開始只有任意的一個節點,就至關於咱們選擇一個節點爲根,

而後進行兩種操做:

1.每次擴展一個節點的兒子,即把一個節點和已經在樹上的一個點連上一條紅邊,且不在這兩個點之間加珠子:

或者擴展一個節點的孫子再擴展這個孫子的爸爸,就是把樹上的一個節點連到另外一個節點上,在把一個節點插到這兩個節點之間,把兩條邊染成藍色,即:

 

PS:若是出現一個根爲藍線的中點,那麼它不多是第一個出現的珠子

好的,假設以1號點爲根,咱們能夠列出一個DP方程式

f[i][0/1]表示當前節點是否爲中點得到的最大價值

$f[i][0]=\sum\limits_{j}^{j \in son[i]}max(f[j][0],f[j][1]+dis(i,j));$

$f[i][1]=f[i][0]+max(f[j][0]-max(f[j][0],f[j][1]+dis(i,j)));(j \in son[i])$

爲了進行換根DP,咱們設$g[i][j][0/1](j \in son[i])$表示f[i][0/1]不考慮兒子j的貢獻所能得到的最大貢獻

也不難求,即:

$g[i][j][0](j \in son[i])=f[i][0]-max(f[j][0],f[j][1]+dis(i,j))$

$g[i][j][1]$同理,記錄一下最大值和次大值便可

而後咱們須要換根進行DP

對於每個兒子,咱們實際上將它的父親當作它的兒子,爲它提供貢獻便可,這個東西仍是直接看代碼好懂一點的吧

void dp2(int x,int y){
    if(!son[x].size()) return;
    if(son[x].size())rep(i,0,son[x].size()-1){
        f[x][0]=g[x][0][i]; f[x][1]=g[x][1][i]; 
        if(fa[x]){
            f[x][0]+=max(f[fa[x]][0],f[fa[x]][1]+y);
            f[x][1]=f[x][0]+max(maxxx[x][i],-max(f[fa[x]][0],f[fa[x]][1]+y)+f[fa[x]][0]+y);
        } 
        ans=max(ans,f[son[x][i]][0]+max(f[x][0],f[x][1]+len[x][i]));
        dp2(son[x][i],len[x][i]);//因爲是dfs的進行Dp,因此f[fa[x]][0/1]表示的就是以fa[x]爲根的最大價值,故能夠這樣直接轉移
    }
}

完結撒花o((>ω< ))o

CODE:

#include<iostream> 
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<vector>
#define rep(i,a,b) for(int i=a;i<=(b);i++)
#define int long long
#define MAXN 200040
using namespace std;
int n,to[MAXN<<1],nxt[MAXN<<1],fir[MAXN],val[MAXN<<1],tot,f[MAXN][2],ans,fa[MAXN];
vector<int> son[MAXN],len[MAXN],g[MAXN][2],maxxx[MAXN];
void ade(int x,int y,int z){
    to[++tot]=y;
    nxt[tot]=fir[x];
    fir[x]=tot;
    val[tot]=z;
}
void dp1(int x,int y){
    fa[x]=y;
    int maxx1=-888888888,maxx2=-888888888;
    for(int k=fir[x];k;k=nxt[k]){
        if(to[k]==y) continue;
        son[x].push_back(to[k]); dp1(to[k],x);
        f[x][0]+=max(f[to[k]][0],f[to[k]][1]+val[k]);
        len[x].push_back(val[k]);
        if(maxx1<-max(f[to[k]][0],f[to[k]][1]+val[k])+f[to[k]][0]+val[k]) maxx2=maxx1,maxx1=-max(f[to[k]][0],f[to[k]][1]+val[k])+f[to[k]][0]+val[k];
        else if(maxx2<-max(f[to[k]][0],f[to[k]][1]+val[k])+f[to[k]][0]+val[k]) maxx2=-max(f[to[k]][0],f[to[k]][1]+val[k])+f[to[k]][0]+val[k];
    }
    f[x][1]=f[x][0]+maxx1;
    if(!son[x].size()) return;
    rep(i,0,son[x].size()-1){
        g[x][0].push_back(f[x][0]-max(f[son[x][i]][0],f[son[x][i]][1]+len[x][i]));
        int tmp=-max(f[son[x][i]][0],f[son[x][i]][1]+len[x][i])+f[son[x][i]][0]+len[x][i];
        if(tmp==maxx1) g[x][1].push_back(g[x][0].back()+maxx2),maxxx[x].push_back(maxx2);
        else g[x][1].push_back(g[x][0].back()+maxx1),maxxx[x].push_back(maxx1);
    }
    
}
void dp2(int x,int y){
    if(!son[x].size()) return;
    if(son[x].size())rep(i,0,son[x].size()-1){
        f[x][0]=g[x][0][i]; f[x][1]=g[x][1][i]; 
        if(fa[x]){
            f[x][0]+=max(f[fa[x]][0],f[fa[x]][1]+y);
            f[x][1]=f[x][0]+max(maxxx[x][i],-max(f[fa[x]][0],f[fa[x]][1]+y)+f[fa[x]][0]+y);
        } 
        ans=max(ans,f[son[x][i]][0]+max(f[x][0],f[x][1]+len[x][i]));
        dp2(son[x][i],len[x][i]);
    }
}
main(){
    scanf("%lld",&n);
    rep(i,1,n-1){
        int x,y,z; scanf("%lld%lld%lld",&x,&y,&z);
        ade(x,y,z); ade(y,x,z); 
    }
    dp1(1,0); dp2(1,-88888888);
    cout<<ans; 
    return 0;
}
相關文章
相關標籤/搜索