連通能力 樹形DP 樹上倍增

2021-08-26 08:21:55 字數 1132 閱讀 1715

對於一棵有邊權的樹(n 個結點 n – 1 條邊的無向連通圖),我們 按以下方法定義其  連通能力:

1、規定某結點的代價為它到其它結點的距離(簡單路徑所經過邊的權值 和)的最大值;  

2、代價最小的結點的代價作為這棵樹的連通能力。

設某棵給定的樹以 1 號結點為根,問以任意結點為根的子樹的連 通能力有多大。

首先看到有關於樹上最長鏈的,能想到樹的直徑。然而題目中還有乙個最小的要求,所以也並不是直徑。

不妨將題目要求的東西定義為「樹的半徑」。因為既在最長鏈上,但又能保持和兩鏈端的距離大致相等,向左移一步,到右邊鏈端的值會變大,答案也會更大,同理向右移也是。所以在中間位置最優,類似帶權中位數,成為既滿足最長距離,也滿足最小代價。

可以證明代價最小的節點一定在樹的直徑上,感性理解一下

樹的直徑?->樹形dp呀

找到了直徑怎麼找中間那個點呢?

想到了lca裡面的倍增,往上跳直徑/2個長度即可

所以說知識掌握要熟練,這道題分析起來比較簡單,知識點都是學過的,可就是寫不來

#include#define n 1000005 

using namespace std;

int first[n],next[n*2],to[n*2],w[n*2],tot;

int n,fa[n][21],f1[n],f2[n],dep[n];

int pos1[n],pos2[n],dis[n],d[n],ans[n];

int read()

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

void dfs(int cur,int f)

else if(f1[t]+w[i]>f2[cur])

} int x=pos1[cur];

if(d[cur]=0;i--)

ans[cur]=f2[cur]+dis[x]-dis[cur];

if(f1[cur]-dis[fa[x][0]]+dis[cur]int main()

dep[1]=1,dfs(1,0);

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

return 0;

}

HAOI2015 樹上染色(樹形dp)

有一棵點數為 n 的樹,樹邊有邊權。給你乙個在 0 n 之內的正整數 k 你要在這棵樹中選擇 k個點,將其染成黑色,並將其他 的n k個點染成白色 將所有點染色後,你會獲得黑點兩兩之間的距離加上白點兩兩之間的距離的和的受益。問受益最大值是多少。輸入格式 第一行包含兩個整數 n,k 接下來 n 1 行...

HAOI2015 樹上染色(樹形dp,樹形揹包)

題目描述 有一棵點數為n的樹,樹邊有邊權。給你乙個在0 n之內的正整數k,你要在這棵樹中選擇k個點,將其染成黑色,並將其他的n k個點染成白色。將所有點染色後,你會獲得黑點兩兩之間的距離加上白點兩兩之間距離的和的收益。問收益最大值是多少。輸入描述 第一行兩個整數n,k。接下來n 1行每行三個正整數f...

poj 1192 最優連通子集 (樹形dp)

設dp u 0 為以u為根的子樹,子集中沒有u的最大權值,dp u 1 則表示子集中有u。如果子集中沒有u,那麼u的所有兒子中只能選乙個。如果子集中有u,那麼u的所有兒子要麼不選,要麼必須在子集中。狀態轉移方程 dp u 0 max dp u 0 max dp v 0 dp v 1 dp u 1 m...