前言
挺有意思,写出来一遍过挺爽的,于是水沝淼㵘一篇博客
题目
讲解
先看弱化版[LNOI2014]LCA
之前的思路是考虑LCA到根上每个点的贡献,用树链剖分维护即可
类似地,我们考虑先对询问按 (x) 从小到大排序
对于每个询问达到 (x) 时,我们对其到根的路径上加上权值
由于本题有一个 (k) 次方,所以我们不能再加 (1),而是应该加上(depth^k(i)-depth^k(i-1))
这样我们如果求出 (y) 到根的路径上的点权和,即求出了答案
我们依然可以区间加一(懒标记),只是每个节点加的权值为上面的那个式子,可以预处理
代码
int qpow(int x,int y)
{
int ret = 1;
while(y){if(y & 1) ret = 1ll * ret * x % MOD;x = 1ll * x * x % MOD;y >>= 1;}
return ret;
}
int head[MAXN],tot;
struct edge
{
int v,nxt;
}e[MAXN];
void Add_Edge(int x,int y)
{
e[++tot].v = y;
e[tot].nxt = head[x];
head[x] = tot;
}
int d[MAXN],siz[MAXN],son[MAXN],f[MAXN];
void dfs1(int x)
{
d[x] = d[f[x]] + 1;
siz[x] = 1;
for(int i = head[x]; i ;i = e[i].nxt)
{
dfs1(e[i].v);
siz[x] += siz[e[i].v];
if(siz[e[i].v] > siz[son[x]]) son[x] = e[i].v;
}
}
int tp[MAXN],dfn[MAXN],dfntot,rdfn[MAXN];
void dfs2(int x,int t)
{
dfn[x] = ++dfntot;
rdfn[dfntot] = x;
tp[x] = t;
if(!son[x]) return;
dfs2(son[x],t);
for(int i = head[x]; i ;i = e[i].nxt)
if(e[i].v != son[x])
dfs2(e[i].v,e[i].v);
}
#define lc (x<<1)
#define rc (x<<1|1)
struct SegmentTree
{
struct node
{
int pre,s,lz;
}t[MAXN << 2];
void down(int x)
{
if(!t[x].lz) return;
t[lc].s = (t[lc].s + 1ll * t[lc].pre * t[x].lz) % MOD;
t[rc].s = (t[rc].s + 1ll * t[rc].pre * t[x].lz) % MOD;
t[lc].lz += t[x].lz; t[rc].lz += t[x].lz;
t[x].lz = 0;
}
void up(int x)
{
t[x].s = (t[lc].s + t[rc].s) % MOD;
}
void Build(int x,int l,int r)
{
if(l == r)
{
t[x].pre = (qpow(d[rdfn[l]],k) - qpow(d[rdfn[l]]-1,k) + MOD) % MOD;
return;
}
int mid = (l+r) >> 1;
Build(lc,l,mid); Build(rc,mid+1,r);
t[x].pre = (t[lc].pre + t[rc].pre) % MOD;
}
void Add(int x,int l,int r,int ql,int qr)
{
if(ql <= l && r <= qr)
{
t[x].lz++;
t[x].s = (t[x].pre + t[x].s) % MOD;
return;
}
down(x);
int mid = (l+r) >> 1;
if(ql <= mid) Add(lc,l,mid,ql,qr);
if(mid+1 <= qr) Add(rc,mid+1,r,ql,qr);
up(x);
}
int Query(int x,int l,int r,int ql,int qr)
{
if(ql <= l && r <= qr) return t[x].s;
down(x);
int mid = (l+r) >> 1,ret = 0;
if(ql <= mid) ret += Query(lc,l,mid,ql,qr);
if(mid+1 <= qr) ret += Query(rc,mid+1,r,ql,qr);
return ret % MOD;
}
}st;
void AddChain(int x)
{
while(x)
{
st.Add(1,1,n,dfn[tp[x]],dfn[x]);
x = f[tp[x]];
}
}
int QueryChain(int x)
{
int ret = 0;
while(x)
{
ret = (ret + st.Query(1,1,n,dfn[tp[x]],dfn[x])) % MOD;
x = f[tp[x]];
}
return ret;
}
struct query
{
int x,y,ID;
bool operator < (const query &px)const{
return x < px.x;
}
}q[MAXN];
int main()
{
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
n = Read(); Q = Read(); k = Read();
for(int i = 2;i <= n;++ i) Add_Edge(f[i] = Read(),i);
for(int i = 1;i <= Q;++ i) q[i].x = Read(),q[i].y = Read(),q[i].ID = i;
sort(q+1,q+Q+1);
dfs1(1);
dfs2(1,1);
st.Build(1,1,n);
int now = 1;
for(int i = 1;i <= Q;++ i)
{
while(now <= q[i].x) AddChain(now++);
ans[q[i].ID] = QueryChain(q[i].y);
}
for(int i = 1;i <= Q;++ i) Put(ans[i],'
');
return 0;
}