bzoj5293 樹上倍增 求和

2021-08-18 22:29:25 字數 1905 閱讀 1584

description

master 對樹上的求和非常感興趣。他生成了一棵有根樹,並且希望多次詢問這棵樹上一段路徑上所有節點深度的k 次方和,而且每次的k

可能是不同的。此處節點深度的定義是這個節點到根的路徑上的邊數。他把這個問題交給 了pupil,但pupil

並不會這麼複雜的操作,你能幫他解決嗎?

input

第一行包含乙個正整數n ,表示樹的節點數。 之後n-1 行每行兩個空格隔開的正整數i,j ,表示樹上的一條連線點i 和點j 的邊。

之後一行乙個正整數m ,表示詢問的數量。 之後每行三個空格隔開的正整數i,j,k ,表示詢問從點i 到點j 的路徑上所有節點深度的k

次方和。 由於這個結果可能非常大,輸出其對998244353 取模的結果。 樹的節點從1 開始標號,其中1 號節點為樹的根。

output

對於每組資料輸出一行乙個正整數表示取模後的結果。 1≤n,m≤300000,1≤k≤50

sample input

1 2

1 32 4

2 51 4 5

5 4 45

sample output

hint

說明

樣例解釋

以下用d(i) 表示第i 個節點的深度。

對於樣例中的樹,有d(1)=0,d(2)=1,d(3)=1,d(4)=2,d(5)=2。

因此第乙個詢問答案為(2^5 + 1^5 + 0^5) mod 998244353 = 33

第二個詢問答案為(2^45 + 1^45 + 2^45) mod 998244353 = 503245989。

題解

你可以發現k<=50,於是我們可以直接預處理每個點到根路徑上的50個和

然後lca跳一跳

就沒了。。

今天狀態真的差lca各種碼錯

#include

#include

#include

#include

#include

using

namespace

std;

typedef

long

long ll;

const ll mod=998244353;

struct node

a[610000];int len,last[310000];

void ins(int x,int y)

int col[310000];

int bin[25],fa[310000][25];

ll dep[310000];

inline

void pre_tree_node(int x)

}}ll sx[310000][55];

inline ll pow_mod(int a,int b)

return ret;

}void work(int x)

}int lca(int x,int y)

ll findsum(int x,int y,int op)

int n,m;

ll ans[310000];

int main()

fa[1][0]=0;dep[1]=1;

pre_tree_node(1);

work(1);

scanf("%d",&m);

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

return

0;}

樹上倍增 求LCA u,v

求lca u,v 的三種方法 1 rmq dfs 序 2 並查集 dfs 3 樹上倍增 然而聽說1,2兩種方法不怎麼火熱,3是目前最受歡迎的,故我就跟隨大眾潮流,學了樹上倍增求lca u,v 的方法 樹上倍增 利用了rmq的思想,首先定義乙個pre i j 陣列,pre i j 表示i往上走2 j層...

樹上倍增法求LCA

我們找的是任意兩個結點的最近公共祖先,那麼我們可以考慮這麼兩種種情況 1.兩結點的深度相同.2.兩結點深度不同.第一步都要轉化為情況1,這種可處理的情況。先不考慮其他,我們思考這麼乙個問題 對於兩個深度不同的結點,把深度更深的那個向其父節點迭代,直到這個迭代結點和另乙個結點深度相同,那麼這兩個深度相...

演算法 樹上倍增求LCA

lca指的是最近公共祖先 least common ancestors 如下圖所示 4和5的lca就是2 那怎麼求呢?最粗暴的方法就是先dfs一次,處理出每個點的深度 然後把深度更深的那乙個點 4 乙個點地乙個點地往上跳,直到到某個點 3 和另外那個點 5 的深度一樣 然後兩個點一起乙個點地乙個點地...