牛客練習賽60 E 旗鼓相當的對手 啟發式合併

2021-10-18 03:18:41 字數 2172 閱讀 1091

傳送門

考慮把每個點拿出來單獨計算

假如樹型dpdp

dp怎麼寫??

定義d ep

[x

]dep[x]

dep[x]

為深度為x

xx的個數,w[x

]w[x]

w[x]

為深度x

xx節點的權值和

那麼新加入一棵子樹時,每個點都可能和之前子樹的節點形成k

kk路徑的lca

lcalc

a 因為d ee

p[u]

+dee

p[v]

−2∗d

eep[

lca(

u,v)

]=

kdeep[u]+deep[v]-2*deep[lca(u,v)]=k

deep[u

]+de

ep[v

]−2∗

deep

[lca

(u,v

)]=k

所以得到子樹中滿足條件的節點深度是dee

p[v]

=2∗d

eep[

lca(

u,v)

]+k−

deep

[u

]deep[v]=2*deep[lca(u,v)]+k-deep[u]

deep[v

]=2∗

deep

[lca

(u,v

)]+k

−dee

p[u]

於是計算完當前子樹的貢獻後,把子樹加入dep

depde

p和ww

w陣列即可

然後發現這其實是個啟發式合併的過程,於是複雜度優化到o(n

log(

n)

)o(nlog(n))

o(nlog

(n))

#include

using

namespace std;

#define int long long

const

int maxn =

3e5+10;

struct edge

d[maxn]

;int head[maxn]

,cnt=1;

void

add(

int u,

int v)

,head[u]

= cnt;

}int n,k,son,siz[maxn]

,deep[maxn]

,ans[maxn]

,dfn[maxn]

,id,f[maxn]

,son[maxn]

,a[maxn]

;void

dfs(

int u,

int fa)

}int dep[maxn]

,w[maxn]

;int

getans

(int u,

int fa)

for(

int j=dfn[v]

;j+siz[v]

;j++)}

dep[deep[u]]++

, w[deep[u]]+

=a[u]

;return res;

}void

dsu(

int u,

int fa,

int keep)

if( son[u]

)dsu

(son[u]

,u,1

),son = son[u]

; ans[u]

=getans

(u,fa)

; son =0;

if( keep )

return

;for

(int i=dfn[u]

;i+siz[u]

;i++)}

signed

main()

dfs(1,

0);dsu(1

,0,1

);for(

int i=

1;i<=n;i++

)printf

("%lld "

,ans[i]);

}

牛客練習賽60補題

思路 考慮位運算 的特性 只有兩者都為1才會對答案有貢獻 且 對答案貢獻的值為 1 k 其中k是當前1所在二進位制下的位數 所以考慮預處理每乙個位的1出現的次數 其中對每一位都會遍歷n n次 所以每一位對答案的貢獻就是 a i a i 1 i a i 為當前位置1的個數 include using ...

操作集錦 牛客網 牛客練習賽60

題目傳送 時間限制 c c 1秒,其他語言2秒 空間限制 c c 262144k,其他語言524288k 64bit io format lld 題目描述 輸入描述 第一行兩個整數n,k 第二行乙個長度為n的字串,保證只存在小寫字母.輸出描述 示例1輸入 3 1 abc輸出 3備註 1 n 1e3 ...

牛客20180601練習賽19 E

已知第i個瓶子的品牌為ai,且其能開啟bi品牌的瓶子.問有幾瓶飲料托公尺無法喝到.被用於開啟飲料瓶的瓶子不一定需要被開啟.乙個瓶子不能開啟其本身.輸入描述 第一行乙個整數n,表示飲料的瓶數.接下來n行,每行兩個整數ai,bi.輸出描述 輸出一行乙個整數,表示小托公尺無法喝到的飲料瓶數.示例1 輸入 ...