【題解】【樹形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肯定是單調遞增...