JZOJ 5691. 【GDOI2018Day2模拟4.25】求和
Description
master對樹上的求和非常感興趣。他生成了一棵有根樹,并且希望多次詢問這棵樹上一段路徑上所有節點深度的k次方和,而且每次的k可能是不同的。此處節點深度的定義是這個節點到根的路徑上的邊數。他把這個問題交給了 Pupil,但Pupil并不會這么復雜的操作,你能幫他解決嗎?
Input
從文件 sum.in 中讀入數據。
第一行包含一個正整數 n,表示樹的節點數。
之后 n?1 行每行兩個空格隔開的正整數 i, j,表示樹上的一條連接點 i 和點 j 的邊。
之后一行一個正整數 m,表示詢問的數量。
之后每行三個空格隔開的正整數 i, j,k,表示詢問從點 i 到點 j 的路徑上所有節點深度的 k 次方和。由于這個結果可能非常大,輸出其對 998244353 取模的結果。
樹的節點從 1 開始標號,其中 1 號節點為樹的根。
Output
輸出到文件 sum.out 中。
對于每組數據輸出一行一個正整數表示取模后的結果。
Sample Input
5
1 2
1 3
2 4
2 5
2
1 4 5
5 4 45
Sample Output
33
503245989
Data Constraint
對于 30% 的數據,1 ≤ n,m ≤ 100。
對于 60% 的數據,1 ≤ n,m ≤ 1000。
對于 100% 的數據,1 ≤ n,m ≤ 300000,1 ≤ k ≤ 50。
【提示】
數據規模較大,請注意使用較快速的輸入輸出方式。
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。
Solution
好不容易的簽到題……
直接倍增+LCA,預處理深度k次方的前綴和。
詢問時求出LCA,因為深度 di 是連續的,我們直接利用前綴和計算即可。
時間復雜度 O(N?log?N) 。
Code
#include<cstdio> #include<algorithm> #include<cmath> #include<cctype> using namespace std; typedef long long LL; const int N=3e5+5,mo=998244353; int tot; int first[N],nex[N<<1],en[N<<1]; int dep[N],q[N],f[N][19],g[N][51]; inline int read() {int X=0,w=0; char ch=0;while(!isdigit(ch)) w|=ch=='-',ch=getchar();while(isdigit(ch)) X=(X<<1)+(X<<3)+(ch^48),ch=getchar();return w?-X:X; } inline void write(int x) {if(x>9) write(x/10);putchar(x%10+'0'); } inline void insert(int x,int y) {nex[++tot]=first[x];first[x]=tot;en[tot]=y; } void dfs(int x) {dep[x]=dep[f[x][0]]+1;for(int i=first[x];i;i=nex[i])if(en[i]^f[x][0]){f[en[i]][0]=x;dfs(en[i]);} } inline int ksm(int x,int y) {int s=1;while(y){if(y&1) s=(LL)s*x%mo;x=(LL)x*x%mo;y>>=1;}return s; } inline int getlca(int x,int y) {if(dep[x]<dep[y]) swap(x,y);for(int i=log2(dep[x]);i>=0;i--)if(dep[f[x][i]]>=dep[y]) x=f[x][i];if(x==y) return x;for(int i=log2(dep[x]);i>=0;i--)if(f[x][i]^f[y][i]) x=f[x][i],y=f[y][i];return f[x][0]; } int main() {freopen("sum.in","r",stdin);freopen("sum.out","w",stdout);int n=read();for(int i=1;i<n;i++){int x=read(),y=read();insert(x,y);insert(y,x);}int l=0,r=q[1]=dep[1]=1;while(l<r){int x=q[++l];for(int i=first[x];i;i=nex[i])if(en[i]^f[x][0]){f[en[i]][0]=x;dep[en[i]]=dep[x]+1;q[++r]=en[i];}}//dfs(1);for(int j=1;j<=50;j++)for(int i=1;i<=n;i++)g[i][j]=(g[i-1][j]+ksm(i-1,j))%mo;for(int j=1;j<19;j++)for(int i=1;i<=n;i++)f[i][j]=f[f[i][j-1]][j-1];int m=read();while(m--){int x=read(),y=read(),k=read();int z=getlca(x,y);int ans=(g[dep[x]][k]+g[dep[y]][k])%mo;ans=(ans-(LL)2*g[dep[z]][k]%mo+mo)%mo;int sum=((LL)g[dep[z]][k]-g[dep[z]-1][k]+mo)%mo;ans=(ans+sum)%mo;write(ans),putchar('\n');}return 0; }總結
以上是生活随笔為你收集整理的JZOJ 5691. 【GDOI2018Day2模拟4.25】求和的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: JZOJ 5689. 【GDOI2018
- 下一篇: 洛谷 P4245 【模板】MTT