傳送門
考慮把每個點拿出來單獨計算
假如樹型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 輸入 ...