题解 P5305 【[GXOI/GZOI2019]旧词】
如果
在上面那道题中,我们提到,要对
思考
如果把1改成
现在的问题是,我们需要用线段树维护一个序列,使得我们可以:
-
对
[l,r] 的每一个数加A[i]=dep[i]^k-(dep[i]-1)^k -
求
[l,r] 的区间和
这非常sb,处理出每个区间
代码如下。
#include<bits/stdc++.h>
using namespace std;
const int tt=998244353;
int N,M,K;
int lnk[50005];
int pre[50005],tgt[50005],cnt;
void add_E(int u,int v){
pre[++cnt]=lnk[u],tgt[cnt]=v,lnk[u]=cnt;
}
int fa[50005],son[50005],s[50005],dep[50005];
int top[50005],seg[50005],rev[50005],idx;
void dfs1(int x){
s[x]=1;dep[x]=dep[fa[x]]+1;
for(int e=lnk[x];e;e=pre[e]){
dfs1(tgt[e]),s[x]+=s[tgt[e]];
if(s[tgt[e]]>s[son[x]]) son[x]=tgt[e];
}
}
void dfs2(int x){
seg[x]=++idx;rev[idx]=x;
if(son[x]) top[son[x]]=top[x],dfs2(son[x]);
for(int e=lnk[x];e;e=pre[e])if(tgt[e]!=son[x])
top[tgt[e]]=tgt[e],dfs2(tgt[e]);
}
int A[50005];
int ANS[50005];
struct Qs{
int u,v,pos;
bool operator <(const Qs b)const{return u<b.u;}
}Q[50005];
int Key[200005],Sum[200005],Lzy[200005];
void push_up(int x){Sum[x]=(Sum[x<<1]+Sum[x<<1|1])%tt;}
void push_down(int x,int l,int r){
int mid=(l+r)>>1;
Sum[x<<1]=(Sum[x<<1]+1LL*Key[x<<1]*Lzy[x]%tt)%tt;
Lzy[x<<1]=(Lzy[x<<1]+Lzy[x])%tt;
Sum[x<<1|1]=(Sum[x<<1|1]+1LL*Key[x<<1|1]*Lzy[x]%tt)%tt;
Lzy[x<<1|1]=(Lzy[x<<1|1]+Lzy[x])%tt;
Lzy[x]=0;
}
void Build(int x,int l,int r){
if(l==r){Key[x]=A[rev[l]];return;}
int mid=(l+r)>>1;
Build(x<<1,l,mid);Build(x<<1|1,mid+1,r);
Key[x]=(Key[x<<1]+Key[x<<1|1])%tt;
}
void Update(int x,int l,int r,int L,int R){
if(L<=l&&r<=R){Sum[x]=(Sum[x]+Key[x]%tt)%tt;Lzy[x]=(Lzy[x]+1)%tt;return;}
push_down(x,l,r);
int mid=(l+r)>>1;
if(L<=mid) Update(x<<1,l,mid,L,R);
if(R>mid) Update(x<<1|1,mid+1,r,L,R);
push_up(x);
}
int Query(int x,int l,int r,int L,int R){
if(L<=l&&r<=R) return Sum[x];
push_down(x,l,r);
int mid=(l+r)>>1,ans=0;
if(L<=mid) ans=(ans+Query(x<<1,l,mid,L,R))%tt;
if(R>mid) ans=(ans+Query(x<<1|1,mid+1,r,L,R))%tt;
push_up(x);
return ans;
}
void Chain_Update(int x){
while(x){
Update(1,1,N,seg[top[x]],seg[x]);
x=fa[top[x]];
}
}
int Chain_Query(int x){
int ans=0;
while(x){
ans=(ans+Query(1,1,N,seg[top[x]],seg[x]))%tt;
x=fa[top[x]];
}
return ans;
}
int now_id=1;
int qpow(int a,int k){
int ans=1;
while(k){
if(k&1) ans=1LL*ans*a%tt;
a=1LL*a*a%tt;
k>>=1;
}
return ans;
}
int main(){
scanf("%d%d%d",&N,&M,&K);
fa[1]=0;
for(int i=2;i<=N;i++) scanf("%d",&fa[i]),add_E(fa[i],i);
dfs1(1);top[1]=1;dfs2(1);
for(int i=1;i<=N;i++) A[i]=(qpow(dep[i],K)-qpow(dep[i]-1,K)+tt)%tt;
Build(1,1,N);
for(int i=1;i<=M;i++){
int r,z;scanf("%d%d",&r,&z);
Q[i].u=r,Q[i].v=z,Q[i].pos=i;
}
sort(Q+1,Q+M+1);
for(int i=1;i<=N;i++){
Chain_Update(i);
while(Q[now_id].u==i&&now_id<=M){
ANS[Q[now_id].pos]=Chain_Query(Q[now_id].v);
now_id++;
}
}
for(int i=1;i<=M;i++) printf("%d\n",ANS[i]);
return 0;
}