好套路的题目,和Luogu P4211 [LNOI2014]LCA基本上就是一个题
先考虑\(\sum{i\le x} \operatorname{depth(\operatorname{lca}(i,y))}\)怎么做(其实就是LNOI那题)
很容易发现此时我们两个点对的贡献为\(\operatorname{lca}\)的深度\(\Leftrightarrow\)两点与根节点公共路径长度
所以我们可以利用莫队+树剖,每次加一个点就是到根的一条链加\(1\),查询就是查某个点到根的路径和,复杂度是\(O(n\sqrt n\log^2 n)\)
然后发现删除其实完全没有必要,因此我们离线一下就变成\(O(n\log^2 n)\)的了
那么考虑这题怎么做,上面的算法相当于这里的\(k=1\),而这个累加的\(1\)其实就是\(( \operatorname{depth}(x)+1)^1-\operatorname{depth}(x)^1\),是一个树上差分的过程
因此这题每个点每次要加上的值就是\(( \operatorname{depth}(x)+1)^k-\operatorname{depth}(x)^k\),乍一看不好维护,其实仔细想一想每次加的都是定值
那么我们线段树处理出所有对应区间的每次增加值的和,修改的时候加上这个值即可。总体复杂度\(O(n\log^2 n)\)
CODE
#include<cstdio>
#include<cctype>
#include<vector>
#include<utility>
#define RI register int
#define CI const int&
#define Tp template <typename T>
using namespace std;
typedef pair <int,int> pi;
const int N=50005,mod=998244353;
struct edge
{
int to,nxt;
}e[N]; int head[N],n,q,k,cnt,anc[N],dep[N],id[N],s[N],x,y,ans[N]; vector <pi> et[N];
class FileInputOutput
{
private:
static const int S=1<<21;
#define tc() (A==B&&(B=(A=Fin)+fread(Fin,1,S,stdin),A==B)?EOF:*A++)
#define pc(ch) (Ftop<S?Fout[Ftop++]=ch:(fwrite(Fout,1,S,stdout),Fout[(Ftop=0)++]=ch))
char Fin[S],Fout[S],*A,*B; int Ftop,pt[15];
public:
Tp inline void read(T& x)
{
x=0; char ch; while (!isdigit(ch=tc()));
while (x=(x<<3)+(x<<1)+(ch&15),isdigit(ch=tc()));
}
Tp inline void write(T x)
{
if (!x) return (void)(pc('0'),pc('\n')); RI ptop=0;
while (x) pt[++ptop]=x%10,x/=10; while (ptop) pc(pt[ptop--]+48); pc('\n');
}
inline void Fend(void)
{
fwrite(Fout,1,Ftop,stdout);
}
#undef tc
#undef pc
}F;
inline void inc(int& x,CI y)
{
if ((x+=y)>=mod) x-=mod;
}
inline int sum(CI a,CI b)
{
int t=a+b; return t>=mod?t-mod:t;
}
inline int sub(CI a,CI b)
{
int t=a-b; return t<0?t+mod:t;
}
inline int quick_pow(int x,int p,int mul=1)
{
for (;p;p>>=1,x=1LL*x*x%mod) if (p&1) mul=1LL*mul*x%mod; return mul;
}
inline void addedge(CI x,CI y)
{
e[++cnt]=(edge){y,head[x]}; head[x]=cnt;
}
class Segment_Tree
{
private:
struct segment
{
int sum,val,tag;
}node[N<<2];
#define ls now<<1
#define rs now<<1|1
#define S(x) node[x].sum
#define V(x) node[x].val
#define T(x) node[x].tag
inline void pushdown(CI now)
{
if (!T(now)) return; T(ls)+=T(now); inc(S(ls),1LL*T(now)*V(ls)%mod);
T(rs)+=T(now); inc(S(rs),1LL*T(now)*V(rs)%mod); T(now)=0;
}
public:
#define TN CI now=1,CI l=1,CI r=n
#define LS ls,l,mid
#define RS rs,mid+1,r
inline void build(TN)
{
if (l==r) return (void)(V(now)=sub(quick_pow(dep[s[l]]+1,k),quick_pow(dep[s[l]],k)));
int mid=l+r>>1; build(LS); build(RS); V(now)=sum(V(ls),V(rs));
}
inline int query(CI beg,CI end,TN)
{
if (beg<=l&&r<=end) return S(now); int mid=l+r>>1,ret=0; pushdown(now);
if (beg<=mid) inc(ret,query(beg,end,LS)); if (end>mid) inc(ret,query(beg,end,RS)); return ret;
}
inline void modify(CI beg,CI end,TN)
{
if (beg<=l&&r<=end) return ++T(now),inc(S(now),V(now)); int mid=l+r>>1; pushdown(now);
if (beg<=mid) modify(beg,end,LS); if (end>mid) modify(beg,end,RS); S(now)=sum(S(ls),S(rs));
}
#undef ls
#undef rs
#undef S
#undef V
#undef T
#undef TN
#undef LS
#undef RS
}SEG;
class Heavy_Light_Division
{
private:
int son[N],top[N],size[N],idx;
public:
#define to e[i].to
inline void DFS1(CI now)
{
size[now]=1; for (RI i=head[now];i;i=e[i].nxt)
{
dep[to]=dep[now]+1; DFS1(to); size[now]+=size[to];
if (size[to]>size[son[now]]) son[now]=to;
}
}
inline void DFS2(CI now,CI topf=1)
{
s[id[now]=++idx]=now; top[now]=topf; if (son[now]) DFS2(son[now],topf);
for (RI i=head[now];i;i=e[i].nxt) if (to!=son[now]) DFS2(to,to);
}
inline int query(int nw,int ret=0)
{
while (top[nw]) inc(ret,SEG.query(id[top[nw]],id[nw])),nw=anc[top[nw]]; return ret;
}
inline void modify(int nw)
{
while (top[nw]) SEG.modify(id[top[nw]],id[nw]),nw=anc[top[nw]];
}
#undef to
}T;
int main()
{
//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
RI i; for (F.read(n),F.read(q),F.read(k),i=2;i<=n;++i)
F.read(anc[i]),addedge(anc[i],i); for (i=1;i<=q;++i)
F.read(x),F.read(y),et[x].push_back(make_pair(y,i));
for (T.DFS1(1),T.DFS2(1),SEG.build(),i=1;i<=n;++i)
{
T.modify(i); for (pi it:et[i]) ans[it.second]=T.query(it.first);
}
for (i=1;i<=q;++i) F.write(ans[i]); return F.Fend(),0;
}