UOJ #105. 【APIO2014】Beads and wires treedp

題意

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

Append(w, v):一個新的珠子 w 和一個已經添加的珠子 v 用紅線連接起來。
Insert(w, u, v):一個新的珠子 w 插入到用紅線連起來的兩個珠子 u,v之間。具體過程是刪去 u,v 之間紅線,分別用藍線連接 u,w 和 w,v。
每條線都有一個長度。遊戲結束後,你的最終得分爲藍線長度之和。

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

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

分析

不妨我們考慮從某個點開始,那麼一定不存在一些跨越當前點的兩個子樹上來因爲加入當前點而變成兩條藍色的邊

那麼我們考慮treedp,發現每次都要跨過兩層點,其實我們只需要知道是不是中間的點即可,f[i][0/1] 表示i子樹內,i這個點是不是中間點的貢獻

然後轉移:

f[i][0]=json[i]max(f[j][0],f[j][1]+cost)

f[i][1]=f[i][0]+maxjson[i](max(f[j][0],f[j][1]+cost)+f[j][0]+cost)

然後就有一個N2 的dp了,常規的,考慮優化,只需要增加一個換跟操作

要記錄某個點x從父親過來的那條邊的代價,還有以下的最大值和次大值:

(max(f[j][0],f[j][1]+cost)+f[j][0]+cost)

代碼

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N = 200010;
const ll inf = 1e9;
inline ll read()
{
  ll p=0; ll f=1; char ch=getchar();
  while(ch<'0' || ch>'9'){if(ch=='-') f=-1; ch=getchar();}
  while(ch>='0' && ch<='9'){p=p*10+ch-'0'; ch=getchar();}
  return p*f;
}

struct node{ll x,y,next,d;}edge[N<<1]; ll len,first[N];
void ins(ll x,ll y,ll d){len++; edge[len].x=x; edge[len].y=y; edge[len].d=d; edge[len].next=first[x]; first[x]=len;}

ll f[N][2] , h1[N] , h2[N] , hp1[N] , hp2[N]; ll g[N][2];
void upd(ll &x,ll y){x = x+y;}
void updh(ll x,ll y,ll d)
{
  if(h1[x] < d)
  {
    h2[x] = h1[x]; hp2[x] = hp1[x];
    h1[x] = d; hp1[x] = y;
  }
  else if(h2[x] < d)
  {
    h2[x] = d; hp2[x] = y;
  }
}
void dfs(ll x,ll fa)
{
  f[x][0] = 0; h1[x] = h2[x] = -inf;
  for(ll k=first[x];k!=-1;k=edge[k].next)
  {
    ll y = edge[k].y;
    if(y==fa) continue;
    dfs(y,x);
    upd(f[x][0] , max(f[y][0] , f[y][1] + edge[k].d) );
    updh(x , y , -max(f[y][0] , f[y][1] + edge[k].d) + f[y][0] + edge[k].d);
  }f[x][1] = f[x][0] + h1[x];
}

ll ans = 0;

void dfs2(ll x,ll fa,ll d)
{
  ans = max(ans , f[x][0] + max(g[x][0] , g[x][1] + d));
  // if(f[x][0] + max(g[x][0] , g[x][1] + d) == 142) printf("%d\n",x);
  for(ll k=first[x];k!=-1;k=edge[k].next)
  {
    ll y = edge[k].y;
    if(y==fa) continue;
    ll tmp = max(g[x][0] , g[x][1] + d);
    ll g0 = tmp + f[x][0] - max(f[y][0] , f[y][1] + edge[k].d);
    g[y][0] = g0;
    if(hp1[x] == y) g[y][1] = g0 + max(h2[x] , -tmp + g[x][0] + d);
    else g[y][1] = g0 + max(h1[x] , -tmp + g[x][0] + d);
    dfs2(y,x,edge[k].d);
  }
}

int main()
{

  ll n = read(); len = 0; memset(first,-1,sizeof(first));
  for(ll i=1;i<n;i++){ll x = read(); ll y = read(); ll d = read(); ins(x,y,d); ins(y,x,d);}

  dfs(1,0);
  g[1][0] = 0; g[1][1] = -inf; dfs2(1,0,-inf);

  return printf("%lld\n",ans),0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章