\(\text{Solution}\)

第一部分参考 \(\text{LNOI2014 LCA}\)
\(k=1\) 时完全可行
因为对于每个 \(i\), 根到 \(y\) 的路径之和恰好是 \(dep[lca]\)
但当 \(k>1\) 呢?
此时我们要想办法弄出一个加数的方式,使根到 \(y\) 的路径之和为 \(dep[lca]^k\)
考虑每个点 \(x\) 加上的权值为 \(dep[x]^k-dep[fa[x]]^k\)
此时加起来就是 \(dep[lca]^k\)
那问题来了,怎么快速让 \(i\) 到根的每个点 \(x\) 加上这种的数
发现对于一个点加上的数总是相同的(即 \(dep[x]^k-dep[fa[x]]^k\)
那么我们就可以以这个数为点的系数,加 \(x\) 就相当于这个点加上了 \(f \cdot x\)
打一棵不需要修改系数的线段树即可

\(\text{Code}\)
#include <cstdio>
#define LL long long
using namespace std;

const int N = 5e4 + 5;
const LL P = 998244353;
int n, q, k, h[N], H[N], tot, Tot;
struct edge{int nxt, to;}e[N];
struct node{int nxt, to, id;}Q[N];

inline LL fpow(LL x, LL y)
{
	LL res = 1;
	for(; y; y >>= 1, x = x * x % P) if (y & 1) res = res * x % P;
	return res;
}

int top[N], fa[N], dfn[N], rev[N], siz[N], son[N], dep[N], dfc;
void dfs1(int x)
{
	siz[x] = 1;
	for(int i = h[x]; i; i = e[i].nxt)
	{
		int v = e[i].to;
		dep[v] = dep[x] + 1, dfs1(v), siz[x] += siz[v];
		if (siz[son[x]] < siz[v]) son[x] = v;
	}
}
void dfs2(int x, int t)
{
	top[x] = t, dfn[x] = ++dfc, rev[dfc] = x;
	if (son[x]) dfs2(son[x], t);
	for(int i = h[x]; i; i = e[i].nxt)
	{
		int v = e[i].to;
		if (v == son[x]) continue;
		dfs2(v, v);
	}
}

#define ls (p << 1)
#define rs (ls | 1)
LL sum[N * 4], f[N * 4], depk[N * 4], tag[N * 4], ans[N];
void build(int p, int l, int r)
{
	if (l == r) return void(f[p] = (depk[rev[l]] - depk[fa[rev[l]]] + P) % P);
	int mid = (l + r) >> 1;
	build(ls, l, mid), build(rs, mid + 1, r);
	f[p] = (f[ls] + f[rs]) % P;
}
inline void pushdown(int p)
{
	if (!tag[p]) return;
	sum[ls] = (sum[ls] + tag[p] * f[ls] % P) % P, tag[ls] += tag[p];
	sum[rs] = (sum[rs] + tag[p] * f[rs] % P) % P, tag[rs] += tag[p];
	tag[p] = 0;
}
void modify(int p, int l, int r, int tl, int tr, int v)
{
	if (tl <= l && r <= tr)
	{
		sum[p] = (sum[p] + f[p] * v % P) % P, tag[p] += v;
		return;
	}
	pushdown(p);
	int mid = (l + r) >> 1;
	if (tl <= mid) modify(ls, l, mid, tl, tr, v);
	if (tr > mid) modify(rs, mid + 1, r, tl, tr, v);
	sum[p] = (sum[ls] + sum[rs]) % P;
}
int query(int p, int l, int r, int tl, int tr)
{
	if (tl <= l && r <= tr) return sum[p];
	pushdown(p);
	int mid = (l + r) >> 1; LL res = 0;
	if (tl <= mid) res = query(ls, l, mid, tl, tr);
	if (tr > mid) res += query(rs, mid + 1, r, tl, tr);
	return res % P;
}

int main()
{
	scanf("%d%d%d", &n, &q, &k);
	for(int i = 2; i <= n; i++) scanf("%d", &fa[i]), e[++tot] = edge{h[fa[i]], i}, h[fa[i]] = tot;
	dep[1] = 1, dfs1(1), dfs2(1, 1);
	for(int i = 1; i <= n; i++) depk[i] = fpow(dep[i], k);
	build(1, 1, n);
	for(int i = 1, x, y; i <= q; i++) scanf("%d%d", &x, &y), Q[++Tot] = node{H[x], y, i}, H[x] = Tot;
	for(int i = 1, x, fx; i <= n; i++)
	{
		x = i;
		for(; x; ) fx = top[x], modify(1, 1, n, dfn[fx], dfn[x], 1), x = fa[fx];
		for(int j = H[i]; j; j = Q[j].nxt)
		{
			x = Q[j].to;
			for(; x; ) fx = top[x], ans[Q[j].id] = (ans[Q[j].id] + query(1, 1, n, dfn[fx], dfn[x])) % P, x = fa[fx];
		}
	}
	for(int i = 1; i <= q; i++) printf("%lld\n", ans[i]);
}