BZOJ3611 大工程(虛樹,動態規劃)

2021-08-20 03:52:27 字數 2195 閱讀 1202

bzoj

國家有乙個大工程,要給乙個非常大的交通網路裡建一些新的通道。

我們這個國家位置非常特殊,可以看成是乙個單位邊權的樹,城市位於頂點上。

在 2 個國家 a,b 之間建一條新通道需要的代價為樹上 a,b 的最短路徑。

現在國家有很多個計畫,每個計畫都是這樣,我們選中了 k 個點,然後在它們兩兩之間 新建 c(k,2)條 新通道。

現在對於每個計畫,我們想知道:

1.這些新通道的代價和

2.這些新通道中代價最小的是多少

3.這些新通道中代價最大的是多少

第一行 n 表示點數。

接下來 n-1 行,每行兩個數 a,b 表示 a 和 b 之間有一條邊。

點從 1 開始標號。 接下來一行 q 表示計畫數。

對每個計畫有 2 行,第一行 k 表示這個計畫選中了幾個點。

第二行用空格隔開的 k 個互不相同的數表示選了哪 k 個點。

輸出 q 行,每行三個數分別表示代價和,最小代價,最大代價。

10 2 1

3 2

4 1

5 2

6 4

7 58 6

9 7

10 9

5 2

5 4

2 10 4

2 5 2

2 6 1

2 6 1

3 3 3

6 6 6

1 1 1

2 2 2

2 2 2

n<=1000000

q<=50000並且保證所有k之和<=2*n

先考慮正常的dp

d

p對於第乙個,總和。設f[

i]f [i

]表示

i i

的子樹中的關鍵點的個數

轉移:sum

+=f[

v]∗(

k−f[

v])∗

len(

i,v)

,f[i

]+=f

[v]' role="presentation">sum

+=f[

v]∗(

k−f[

v])∗

len(

i,v)

,f[i

]+=f

[v]s

um+=

f[v]

∗(k−

f[v]

)∗le

n(i,

v),f

[i]+

=f[v

]對於第二個和第三個,相當於維護樹上最長鏈和最短鏈

這個就非常基礎了,不寫了。

現在再把這個dp

d

p放在虛樹上做就行了

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

using

namespace

std;

#define ll long long

#define rg register

#define max 1001000

inline

int read()

struct linee[max<<1];

int h[max],cnt=1;

inline

void add(int u,int v,int w);h[u]=cnt++;}

int n,q,k;

int fa[max],size[max],hson[max],dep[max],top[max],dfn[max],low[max],tim;

void dfs1(int u,int ff)

}void dfs2(int u,int tp)

low[u]=tim;

}int lca(int u,int v)

}int main()

dfs1(1,0);dfs2(1,1);

memset(h,0,sizeof(h));

q=read();

while(q--)

return

0;}

BZOJ3611 大工程(虛樹,動態規劃)

bzoj 國家有乙個大工程,要給乙個非常大的交通網路裡建一些新的通道。我們這個國家位置非常特殊,可以看成是乙個單位邊權的樹,城市位於頂點上。在 2 個國家 a,b 之間建一條新通道需要的代價為樹上 a,b 的最短路徑。現在國家有很多個計畫,每個計畫都是這樣,我們選中了 k 個點,然後在它們兩兩之間 ...

bzoj3611 大工程 虛樹 dp

國家有乙個大工程,要給乙個非常大的交通網路裡建一些新的通道。我們這個國家位置非常特殊,可以看成是乙個單位邊權的樹,城市位於頂點上。在 2 個國家 a,b 之間建一條新通道需要的代價為樹上 a,b 的最短路徑。現在國家有很多個計畫,每個計畫都是這樣,我們選中了 k 個點,然後在它們兩兩之間 新建 c ...

Luogu P4103大工程(虛樹DP)

題目鏈結 我貌似發現這類dp就是先別管什麼虛樹 把樹形dp搞出來套上虛樹板子就好了 這個樹形dp就是設sum為答案,sumd為子樹內所有點的深度和 當然指的是被詢問的點 maxi指子樹內最深的點的深度,mini同理 然後考慮我們dfs到x,它的兒子已經遍歷到一半,新加進來乙個兒子to 顯然 sum ...