NOIP 模擬題 T2 寶藏(樹形dp)

2021-07-24 14:47:28 字數 1464 閱讀 2735

【題解】【樹形dp】

【其實這道題說起來很簡單,用四個陣列:d1、d0、u0、u1分別表示從當前點向下更新,不返回;從當前點向下更新再回到當前點;從當前點向上更新回到當前點;從當前點向上更新不返回。用兩遍dfs求出這四個陣列】

【實現起來細節會比較多,耐心處理】

#include#include#include#define ll long long

using namespace std;

int a[600010],nxt[600010],p[300010],tot,n;

ll ans[300010],w[600010],val[300010];

ll d1[300010],d0[300010],u1[300010],u0[300010];//0表示返回,1表示不返回;d0表示從下面返回,u0表示從上面返回;d1表示從下面返回,u1表示從上面返回

inline void add(int x,int y,ll z)

void dfs(int x,int fa)

d0[x]+=val[x]; d1[x]=sum+d0[x];//加上當前點的寶藏價值;更新不走回來的最優值

}void dfs(int x,int fa,ll len)

//把當前點從當前路徑往下走獲得的答案減去,用從上面走到當前點的答案更新走到當前點兒子的答案

ll mx1=0,mx2=0;

for(int i=p[x];i!=-1;i=nxt[i])

if(a[i]!=fa)

ll sum=0;

if(u0[x]-2*len>0) sum=len+u1[x]-u0[x];

else sum=u1[x]-len;

if(sum>mx1) mx2=mx1,mx1=sum;

else

if(sum>mx2) mx2=sum;

for(int i=p[x];i!=-1;i=nxt[i])

if(a[i]!=fa)

for(int i=p[x];i!=-1;i=nxt[i])

if(a[i]!=fa) dfs(a[i],x,w[i]);

}int main()

for(i=p[1];i!=-1;i=nxt[i])

//計算最優值

ans[1]=d1[1];//因為把1作為根節點,所以它不可能從上面更新過來

for(i=p[1];i!=-1;i=nxt[i]) dfs(a[i],1,w[i]);

for(i=1;i<=n;++i) printf("%i64d\n",ans[i]);

return 0;

}

(noip 模擬 染色)《樹形DP

染色 題目描述 有一棵點數為 n 的樹,樹邊有邊權。將 m 個點染成黑色,並將其他的點染 成白色。會獲得黑點兩兩之間的距離和加上白點兩兩之間的距離和的收益。問 收益最大值是多少。輸入格式 第一行兩個整數 n m。接下來 n 1 行,每行三個整數 a b c,表示有一 條樹邊連線 a b,長度為 c。...

NOIP校內模擬 T2 字胡串(分治)

lst神仙 這是他的做法 吊了標算 對於這種有多少區間滿足要求的 我們套路的用分治做 每次都統計左端點在左半邊 右端點在右半邊的個數 設f i 表示當前點到中間分割點的最大值,g i 表示當前點到中間分割點的或和 我們發現 g i f i 所以只需找到g i f i 的區間就好 然後f肯定是單調遞增...

NOIP校內模擬 T2 字胡串(分治)

lst神仙 這是他的做法 吊了標算 對於這種有多少區間滿足要求的 我們套路的用分治做 每次都統計左端點在左半邊 右端點在右半邊的個數 設f i 表示當前點到中間分割點的最大值,g i 表示當前點到中間分割點的或和 我們發現 g i f i 所以只需找到g i f i 的區間就好 然後f肯定是單調遞增...