洛谷 & 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...