題解 HNOI 2014 世界樹

2021-08-20 15:21:36 字數 3226 閱讀 5098

洛谷 & bzoj & loj

題目概要:

給定一棵

n n

個節點的樹,

q' role="presentation">q

q次詢問:給定

m m

個關鍵點,每個原樹上的點被最近且序號最小的關鍵點控制,問每個關鍵點(n,

q,∑m

≤300000

' role="presentation">n,q

,∑m≤

300000n,

q,∑m

≤300000

)觀察資料限制:∑m

≤300000

∑ m≤

300000

類似於這種總和限制的題目應該要想到虛樹

先建出虛樹,考慮如何統計答案

很容易想到一條邊上的點只有可能被最靠近邊兩端點的關鍵點控制,所以應該求出虛樹上每個點最接近的關鍵點

對於每一條邊兩端點為x,

y x,y

,控制這兩個點的標號為tx

,ty tx,

ty: 如果t

x=ty

t x=

ty,則這條邊上的貢獻應全部屬於tx

t

x如果t

x≠ty

t x≠

ty,則肯定存在乙個點in

v inv

將這條邊劃分開來,其中

x x

~inv' role="presentation">inv

inv,

inv inv

~y y

的貢獻分別屬於tx

,ty' role="presentation">tx,

tytx

,ty,這裡可以用類似於lca的倍增求解

相應的,虛樹上有沒有體現的點,比如下圖中黑色點為關鍵點,則綠色部分並不會在虛樹中體現

所以這些點就必須將貢獻交給最近的關鍵節點,設re

st[x

] res

t[x]

表示在虛樹中未出現歸到這個點的節點數量,則re

st[x

] res

t[x]

應等於

x x

在原樹上的sz

' role="presentation">szs

z減去在虛樹上的szsz

求lca還是樹剖快,但在求切分點時應用lca方法求解,所以我打了樹剖求lca加倍增求切分,我們推薦用rm

q rmq

來做這題搞清楚細節就不是很難了

#include

using

namespace

std;

typedef

long

long ll;

#define rg register

template

inline _tp read(_tp&x)

const

int n=301000,m=21;

struct edgea[n<<1];

int head[n],anc[n][m],sz[n],son[n],ltop[n],fa[n],depth[n],dfn[n],num[n],f[n],sta[n],vis[n];

int b[n],c[n],rest[n];

int n,m,q,_,dfc,tot,top;

inline

int cmp(const

int&aa,const

int&bb)

inline

void dfs1(int x,int dad)

return ;

}inline

void dfs2(int x,int top)

inline

int lca(int x,int y)

if(depth[x]>depth[y])swap(x,y);

return x;

}inline

int dis(int x,int y)

inline

void dfs3(int x)

}return ;

}inline

void dfs4(int x)

inline

void count(int x,int y)

else ty=fa[ltop[ty]];

if(ltop[x]==ltop[ty])ty=son[x];

rest[x]-=sz[ty];

if(num[x]==num[y])

int inv=y,t1,t2;

for(rg int i=19;~i;--i)

if(depth[anc[inv][i]]>depth[x])

f[num[x]]+=sz[ty]-sz[inv];

f[num[y]]+=sz[inv]-sz[y];

return ;

}int main()

sort(b+1,b+m+1,cmp);

if(num[1]!=1)sta[top=1]=1;

for(rg int i=1;i<=m;++i)

else

if(depth[o]break;}

else

break;

}if(sta[top]!=o)sta[++top]=o;

sta[++top]=x;

}while(top>1)

dfs3(1);dfs4(1);

for(rg int x=1;x<=tot;++x)

for(rg int i=head[vis[x]];i;i=a[i].nxt)

count(vis[x],a[i].v);

for(rg int i=1;i<=tot;++i)f[num[vis[i]]]+=rest[vis[i]];

for(rg int i=1;iprintf("%d ",f[c[i]]);

printf("%d\n",f[c[m]]);

for(rg int i=1;i<=tot;++i)

head[vis[i]]=f[vis[i]]=num[vis[i]]=0;

}return

0;}

題解 HNOI2014 世界樹

hnoi2014 世界樹 從資料範圍很容易看出是個虛樹dp 可惜看出來了也還是不會做 虛樹大家應該都會,不會的話自己去搜吧,我懶得講了,我們在這裡只需要考慮如何dp即可 首先我們需要求出每個點被哪個點所控制,設 u 點被 bl u 所控制,兩遍dfs即可,考慮兒子對父親的影響和父親對兒子的影響 細節...

P3233 HNOI2014 世界樹(虛樹)

看到 mi 300000自然聯想到虛樹,簡單思考一下似乎可行,但剩下的部分貌似就比較麻煩。首先對重新構建的虛樹,考慮每個點應該被誰管。因為乙個點既可以被它子樹中的點管,也可以被子樹以外的點管,所以我們做兩次dfs。第一次先遍歷子節點,再更新,記錄的是乙個點子樹中最近的管他的點是誰。第二次先用從父節點...

虛數 BZOJ3572 HNOI2014 世界樹

給出一顆樹,每次選中m個點,對於樹上任意乙個點,會被其最近的乙個選中點包含 相同有編號小優先 求每個選中點包含了多少個點。之前寫過兩次都沒寫部落格。結果複習板題的時候,連題意都不知道。方法就是虛數板子 include include include include define sf scanf d...