求和VII 倍增法求LCA 樹上差分

2021-08-25 11:56:32 字數 1856 閱讀 7891

時間限制: 2 sec  記憶體限制: 256 mb

提交: 578  解決: 80

[提交] [狀態] [討論版] [命題人:admin]

題目描述

master對樹上的求和非常感興趣。他生成了一棵有根樹,並且希望多次詢問這棵樹上一段路徑上所有節點深度的k次方和,而且每次的k可能是不同的。此處節點深度的定義是這個節點到根的路徑上的邊數。他把這個問題交給了pupil,但pupil並不會這麼複雜的操作,你能幫他解決嗎?

輸入第一行包含乙個正整數n,表示樹的節點數。

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

之後一行乙個正整數m,表示詢問的數量。

之後每行三個空格隔開的正整數i,j,k,表示詢問從點i到點j的路徑上所有節點深度的k次方和。由於這個結果可能非常大,輸出其對998244353取模的結果。

樹的節點從1開始標號,其中1號節點為樹的根。

輸出對於每組資料輸出一行乙個正整數表示取模後的結果。

樣例輸入

5

1 21 3

2 42 5

21 4 5

5 4 45

樣例輸出

33

503245989

提示

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

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

因此第乙個詢問答案為(25+15+05) mod 998244353=33,第二個詢問答案為(245+145+245) mod 998244353=503245989。

對於30%的資料,1≤n,m≤100;

對於60%的資料,1≤n,m≤1000;

對於100%的資料,1≤n,m≤300000,1≤k≤50。

北京oi2018

[提交] [狀態]

因為k比較小,所以預處理k

然後用lca求樹上最近公共祖先l

計算時用 val(u,k) + val(v,k) - val(l,k) - val(fa(l),k) 公式

**:

#include using namespace std;

const int maxn=3e5+100;

#define inf 0x3f3f3f;

const int mod=998244353;

typedef long long ll;

ll val[maxn][60];

int nextt[maxn<<1];

int head[maxn<<1];

int s[maxn<<1];

int cnt = 0;

int fa[maxn][50];

ll dep[maxn<<1];

ll c[100];

bool vis[maxn<<1];

void add(int u,int v)

void dfs(int u)

for(int i=head[u]; i; i=nextt[i])

for(int j=1; j<=50; j++)

dfs(v);

}}int lca(int u,int v)

d >>= 1;

}if(u == v)

return u;

for(int i=20; i>=0; i--)

}return fa[u][0];

}int main()

dfs(1);

int m,w;

scanf("%d",&m);

while(m--)

return 0;

}

樹上倍增法求LCA

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

12 16 樹上倍增法求LCA

1.預處理 節點的深度d 到根節點的距離dist 該點向上走2 k步能夠到達的點 f陣列。2.lca 將兩個節點調整到同乙個深度,只調整深的那個即可。如果 結束後,這兩個點重合,說明該點就是所求的點。否則,從大往小開始試跳躍的步數,直至將這兩個點調整為目標點的兩個子節點。最後兩點的父節點就是所求的l...

演算法 樹上倍增求LCA

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