给定一棵 \(n\) 个点的有根树,节点标号 \(1 \sim n\),\(1\) 号节点为根。ios
给定常数 \(k\)。
给定 \(Q\) 个询问,每次询问给定 \(x,y\)。git
求:
\[ \sum\limits_{i \le x} \text{depth}(\text{lca}(i,y))^k \]spa
\(\text{lca}(x,y)\) 表示节点 \(x\) 与节点 \(y\) 在有根树上的最近公共祖先。
\(\text{depth}(x)\) 表示节点 \(x\) 的深度,根节点的深度为 \(1\)。
因为答案可能很大,你只须要输出答案模 \(998244353\) 的结果。code
当 \(k=1\) 的时候就是 [LNOI2014]LCA.ip
当 \(k\not =1\) 的时候其实本质上是同样的,咱们须要保证加入一个节点 \(x\) 的对 \(y\) 的贡献为 \(depth(lca(x,y))^k\) ,那么咱们能够构造一个序列,把 \(x\) 到根路径上所有加上这段序列后查询 y 到根的路径和会新增 \(depth(lca(x,y))^k\),因此令这个序列为 \(A\),则 \(A_i=dep(i)^k-dep(i-1)^k\),因为路径深度是连续的,因此巧妙地差分掉了,其他的作法和上面那道题类似,再也不赘述。get
#include <iostream> #include <vector> #include <cstdio> #include <cstring> #include <algorithm> #include <fstream> using namespace std; #define LL long long #define SZ(x) ((int)x.size()) #define ALL(x) (x).begin(), (x).end() #define MP(x, y) std::make_pair(x, y) #define DE(x) cout << #x << " = " << x << endl #define DEBUG(...) fprintf(stderr, __VA_ARGS__) #define GO cerr << "GO" << endl; inline void proc_status() { ifstream t("/proc/self/status"); cerr << string(istreambuf_iterator<char>(t), istreambuf_iterator<char>()) << endl; } template<class T> inline T read() { register char c; register T x(0), f(1); while (!isdigit(c = getchar())) if (c == '-') f = -1; while (x = (x << 1) + (x << 3) + (c xor 48), isdigit(c = getchar())); return x * f; } template<typename T> inline bool chkmin(T &a, T b) { return a > b ? a = b, 1 : 0; } template<typename T> inline bool chkmax(T &a, T b) { return a < b ? a = b, 1 : 0; } const int maxN=5e4; #define mod (998244353) inline void Mod(int& x) { x>=mod?x-=mod:0;} LL qpow(LL a,LL b) { LL ans(1); while(b) { if(b&1)ans=ans*a%mod; a=a*a%mod; b>>=1; } return ans; } int n,Q,k; int ver[maxN<<1],nxt[maxN<<1],head[maxN+2],tot; int A[maxN+2],dfn[maxN+2],son[maxN+2],size[maxN+2],dep[maxN+2],rev[maxN+2],dfst,top[maxN+2],fa[maxN+2]; int sum[maxN<<2],tag[maxN<<2]; void link(int u,int v) { ver[++tot]=v,nxt[tot]=head[u],head[u]=tot; } void DFS1(int u,int f) { fa[u]=f; dep[u]=dep[f]+1; size[u]=1; for(int i=head[u];i;i=nxt[i]) { int v=ver[i]; if(v==f)continue; DFS1(v,u); size[u]+=size[v]; if(size[son[u]]<size[v])son[u]=v; } } void DFS2(int u,int topf) { dfn[u]=++dfst; rev[dfst]=u; top[u]=topf; if(son[u])DFS2(son[u],topf); for(int i=head[u];i;i=nxt[i]) { int v=ver[i]; if(v==son[u]||v==fa[u])continue; DFS2(v,v); } } void init() { DFS1(1,0); DFS2(1,1); for(int i=1;i<=n;++i) A[i]=(A[i-1]+qpow(dep[rev[i]],k)-qpow(dep[rev[i]]-1,k)+mod)%mod; } void push(int x,int v,int l,int r) { tag[x]+=v; sum[x]+=(LL)(A[r]-A[l-1]+mod)*v%mod; Mod(sum[x]); } void pushdown(int x,int l,int r) { if(tag[x]) { int mid((l+r)>>1); push(x<<1,tag[x],l,mid); push(x<<1|1,tag[x],mid+1,r); tag[x]=0; } } void add(int x,int l,int r,int L,int R) { if(L<=l&&r<=R) return push(x,1,l,r); int mid=(l+r)>>1; pushdown(x,l,r); if(L<=mid)add(x<<1,l,mid,L,R); if(mid<R)add(x<<1|1,mid+1,r,L,R); sum[x]=sum[x<<1]+sum[x<<1|1],Mod(sum[x]); } int query(int x,int l,int r,int L,int R) { if(L<=l&&r<=R) return sum[x]; int mid=(l+r)>>1; pushdown(x,l,r); int ans(0); if(L<=mid)ans+=query(x<<1,l,mid,L,R); if(mid<R)ans+=query(x<<1|1,mid+1,r,L,R),Mod(ans); return ans; } vector<pair<int, int> >q[maxN+2]; int ans[maxN+2]; int main() { #ifndef ONLINE_JUDGE freopen("xhc.in", "r", stdin); freopen("xhc.out", "w", stdout); #endif n=read<int>(),Q=read<int>(),k=read<int>(); for(int i=2;i<=n;++i) { int f(read<int>()); link(f,i); link(i,f); } init(); for(int i=1;i<=Q;++i) { int x(read<int>()),y(read<int>()); q[x].push_back(MP(y,i)); } for(int i=1;i<=n;++i) { int u=i; while(u) { add(1,1,n,dfn[top[u]],dfn[u]); u=fa[top[u]]; } for(int j=0;j<SZ(q[i]);++j) { int u=q[i][j].first,id=q[i][j].second,res=0; while(u) { res+=query(1,1,n,dfn[top[u]],dfn[u]); Mod(res); u=fa[top[u]]; } ans[id]=res; } } for(int i=1;i<=Q;++i) printf("%d\n",ans[i]); return 0; }