【题目描述】
浮生有梦三千场
穷尽千里诗酒荒
徒把理想倾倒
不如早还乡
温一壶风尘的酒
独饮往事迢迢
举杯轻思量
泪如潮青丝留他方
——乌糟兽/愚青《旧词》
你已经解决了五个问题,不妨在这大树之下,吟唱旧词一首抒怀。最后的问题就是关于这棵树的,它的描述很简单。给定一棵 n 个点的有根树,节点标号 1∼n,1号节点为根。给定常数 k。给定 Q 个询问,每次询问给定 x,y。求:
∑
i
≤
x
d
e
p
t
h
(
l
c
a
(
i
,
y
)
)
k
∑_{i≤x}depth(lca(i,y))^k
∑i≤xdepth(lca(i,y))k
l
c
a
(
x
,
y
)
lca(x,y)
lca(x,y) 表示节点 x 与节点 y 在有根树上的最近公共祖先。
d
e
p
t
h
(
x
)
depth(x)
depth(x)表示节点x 的深度,根节点的深度为 1。
由于答案可能很大,你只需要输出答案模998244353 的结果。
【思路】
这题就是LNOI2014LCA玩剩下的套路。我们先讨论LNOI2014LCA中k=1的情况。我们其实并不需要求出LCA是谁来确定它的深度,还有另一种拓展性更强的方法。
如图,我们要求LCA(x,y)的深度。那么我们先将x到根节点的路径上的点的权值全部加1,然后我们查询y到根节点的路径上所有点的权值之和就是LCA的深度。不要小看这样的方法,它对于多个x的情况也是成立的。即我们把[l,r]的点到根节点的路径上的权值全部加1,那么查询y到根节点的路径的和,查出的就是
∑
i
=
l
r
d
e
p
t
h
(
l
c
a
(
i
,
y
)
)
\sum_{i=l}^rdepth(lca(i,y))
∑i=lrdepth(lca(i,y))。所以我们只需要依次将每个点进行链加操作,每次操作后通过链查询回答有关询问,对于询问[l,r],只需拆成
q
u
e
r
y
(
r
)
−
q
u
e
r
y
(
l
−
1
)
query(r)-query(l-1)
query(r)−query(l−1)即可。时间复杂度O(
n
log
2
n
n\log^2 n
nlog2n)。对于k不等于1的情况也是类似的,我们刚刚的方法的本质就是把深度进行了差分,对于这道题我们把
d
e
p
k
dep^k
depk也进行差分即可,即赋予每个节点u一个权值
v
a
l
=
d
e
p
[
u
]
k
−
(
d
e
p
[
u
]
−
1
)
k
val=dep[u]^k-(dep[u]-1)^k
val=dep[u]k−(dep[u]−1)k,每次将到根节点路径上每个点加上它自己的权值即可,由于这个操作可以打lazy标记,所以线段树时间复杂度没有问题。
代码:
#include<bits/stdc++.h>
#include<tr1/unordered_map>
#define re register
using namespace std;
const int N=5e5+5;
const int mod=998244353;
int n,m,a,b,c,k;
inline int red(){
int data=0;int w=1; char ch=0;
ch=getchar();
while(ch!='-' && (ch<'0' || ch>'9')) ch=getchar();
if(ch=='-') w=-1,ch=getchar();
while(ch>='0' && ch<='9') data=(data<<3)+(data<<1)+ch-'0',ch=getchar();
return w==1?data:-data;
}
int val[N],dep[N],fa[N],son[N],siz[N],rev[N],seg[N],top[N],tot=0;vector<int>g[N];
inline int add(const int&a,const int&b){return (a+b)>=mod?a+b-mod:a+b;}
inline int dec(const int&a,const int&b){return (a-b)<0?a-b+mod:a-b;}
inline int mul(const int&a,const int&b){return 1ll*a*b%mod;}
inline int ksm(int a,int b){
int ret=1;
while(b){if(b&1)ret=mul(ret,a);a=mul(a,a);b>>=1;}
return ret;
}
namespace sgt{
#define lc (p<<1)
#define rc (p<<1|1)
int sum[N<<2|1],ans[N<<2|1],laz[N<<2|1];
inline void pushup(const int &p){ans[p]=add(ans[lc],ans[rc]);}
inline void pushnow(const int&p,const int&v){laz[p]+=v;ans[p]=add(ans[p],mul(v,sum[p]));}
inline void pushdown(const int&p){if(laz[p])pushnow(lc,laz[p]),pushnow(rc,laz[p]),laz[p]=0;}
inline void build(const int&p,const int&l,const int&r){
if(l==r)return(void)(sum[p]=val[dep[rev[l]]]);
int mid=(l+r)>>1;
build(lc,l,mid);build(rc,mid+1,r);
sum[p]=add(sum[lc],sum[rc]);
}
inline void change(const int&p,const int&l,const int&r,const int&ql,const int&qr,const int&v){
if(ql<=l&&qr>=r)return pushnow(p,v);
int mid=(l+r)>>1;pushdown(p);
if(ql<=mid)change(lc,l,mid,ql,qr,v);
if(qr>mid)change(rc,mid+1,r,ql,qr,v);
pushup(p);
}
inline int query(const int&p,const int&l,const int&r,const int&ql,const int&qr){
if(ql<=l&&qr>=r)return ans[p];
int mid=(l+r)>>1,res=0;pushdown(p);
if(ql<=mid)res=add(res,query(lc,l,mid,ql,qr));
if(qr>mid)res=add(res,query(rc,mid+1,r,ql,qr));
return res;
}
}
inline void dfs1(int u){siz[u]=1;int v;
for(int re i=g[u].size()-1;~i;--i){
dep[v=g[u][i]]=dep[u]+1;dfs1(v);siz[u]+=siz[v];
if(siz[v]>siz[son[u]])son[u]=v;
}
}
inline void dfs2(int u){int v;
if(son[u]){
seg[son[u]]=++tot;rev[tot]=son[u];
top[son[u]]=top[u];dfs2(son[u]);
}for(int re i=g[u].size()-1;~i;--i)
if(!top[v=g[u][i]])
seg[v]=++tot,rev[tot]=v,top[v]=v,dfs2(v);
}
inline int qroad(int p){
int fx=top[p],res=0;
while(p)res=add(res,sgt::query(1,1,n,seg[fx],seg[p])),p=fa[fx],fx=top[p];
return res;
}
inline void croad(int p){
int fx=top[p];
while(p)sgt::change(1,1,n,seg[fx],seg[p],1),p=fa[fx],fx=top[p];
}
struct node{
int r,y,id;
friend inline bool operator<(const node&a,const node&b){return a.r<b.r;}
}q[N];
int ans[N];
int main(){n=red();m=red();k=red();
for(int re i=1;i<=n;i++)val[i]=ksm(i,k);
for(int re i=n;i;--i)val[i]=dec(val[i],val[i-1]);
for(int re i=2;i<=n;++i)g[fa[i]=red()].push_back(i);
dfs1(dep[1]=1);top[1]=seg[1]=tot=1;
dfs2(rev[tot]=1);sgt::build(1,1,n);
for(int re i=1;i<=m;i++)q[i]=(node){red(),red(),i};
sort(q+1,q+m+1);int r=0;
for(int re i=1;i<=m;i++){
while(r<q[i].r)croad(++r);
ans[q[i].id]=qroad(q[i].y);
}for(int re i=1;i<=m;i++)
printf("%d\n",ans[i]);
}