1. 程式人生 > >清橙A1212:剪枝

清橙A1212:剪枝

space ans pac log gpo inline main tsinsen getchar()

題面

清橙

Sol

一種新的樹上\(DP\)姿勢
從左往右按鏈\(DP\)

做法:
維護兩個棧\(S1\)\(S2\)
\(S1\)存當前的鏈
\(S2\)存分叉點以下要改的鏈
\(Dfs\),弄一個分叉點,之前的鏈經過它,並且另一條要轉移到的鏈也經過它
那麽每次在葉節點時就把\(S1\)最下面的一部分變成\(S2\)

轉移
兩種情況:
最大值在\(S1\)和在\(S2\)的情況
那麽枚舉\(S2\)\(S1\)中小於\(S2\)的枚舉的值的點就可以轉移,並維護\(S1\)\(S2\)的前綴最大值
再枚舉\(S2\),利用前綴最大值,\(S1\)的大於等於\(S2\)的轉移

# include <bits/stdc++.h>
# define RG register # define IL inline # define Fill(a, b) memset(a, b, sizeof(a)) # define File(a) freopen(a".in", "r", stdin), freopen(a".out", "w", stdout) using namespace std; typedef long long ll; const int _(1e5 + 5); IL int Input(){ RG int x = 0, z = 1
; RG char c = getchar(); for(; c < '0' || c > '9'; c = getchar()) z = c == '-' ? -1 : 1; for(; c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48); return x * z; } int n, val[_], f[_], ans = -2e9; int
fa[_], S1[_], S2[_], id[_], maxv[_]; vector <int> edge[_]; IL void Dfs(RG int u, RG int top){ //top是分叉點在S1中的位置 if(!top) S1[++S1[0]] = u, id[u] = S1[0], f[u] = val[u]; //初始第一條鏈 RG int l = edge[u].size(); if(l){ //非葉子節點不做更新 for(RG int i = 0; i < l; ++i){ RG int v = edge[u][i]; if(!i){ //最左邊的直接加入S2 if(top) S2[++S2[0]] = v; Dfs(v, top); } else S2[S2[0] = 1] = v, Dfs(v, id[u]); //新開一條鏈 } return; } if(!top) return; RG int mx1 = val[S1[top]], maxf = ans, now = top, mx2 = mx1; for(RG int i = 1; i <= S2[0]; ++i){ //最大值在S2中的情況 while(now < S1[0] && val[S1[now]] <= mx1){ //計算每個最大值的貢獻 mx2 = max(mx2, val[S1[now]]); maxf = max(maxf, f[S1[++now]]); maxv[S1[now]] = mx2; //維護S1前綴最大值 } f[S2[i]] = maxf - mx1; //轉移 maxv[S2[i]] = mx1; //維護S2前綴最大值 mx1 = max(mx1, val[S2[i]]); //下一個點 } while(now < S1[0]){ //處理剩下的 mx2 = max(mx2, val[S1[now]]); maxv[S1[++now]] = mx2; } maxf = ans, now = S1[0]; for(RG int i = S2[0]; i; --i){ //最大值在S1中的情況 while(now > top && maxv[S1[now]] >= maxv[S2[i]]){ maxf = max(maxf, f[S1[now]] - maxv[S1[now]]); --now; } f[S2[i]] = max(f[S2[i]], maxf); } for(RG int i = 1; i <= S2[0]; ++i){ //更新到下一條鏈 f[S2[i]] += val[S2[i]]; S1[top + i] = S2[i]; id[S2[i]] = top + i; } S1[0] = top + S2[0]; } int main(RG int argc, RG char* argv[]){ File("cut"); n = Input(), Fill(f, -127); for(RG int i = 1, t; i <= n; ++i){ val[i] = Input(), t = Input(); for(RG int j = 1, tt; j <= t; ++j) tt = Input(), edge[i].push_back(tt); } Dfs(1, 0); for(RG int i = 1; i <= S1[0]; ++i) ans = max(ans, f[S1[i]]); printf("%d\n", ans); return 0; }

清橙A1212:剪枝