题目大意
给出一个n个节点的有根树(编号为0到n-1,根节点为0)。一个点的深度定义为这个节点到根的距离+1。
有q次询问,每次询问给出l r z,求
∑ri=ldeep[LCA(i,z)]
。
Solution
我们可以发现,这个答案是可减得。所以对每次询问,只要求出
(∑ri=1)
-
(∑l−1i=1)
即可。
对于x,z的LCA的深度。就是x,z到根路径中点的交集的点数。所以把x到根的路径上每个点+1,再询问z到根的路径和就可以。对每个询问的l,r,我们按照大小依次加点并查询就可以。
所以问题就变成了维护两种操作:x到根的路径都+1,询问x到根的路径的和。用树链剖分维护。
代码
#include<cstdio>
#include<algorithm>
#define mo 201314
using namespace std;
struct node{
int x,z,id,c;
}q[100010];
typedef long long ll;
int next[300010],num,head[300010],vet[300010],tag[300010],top[300010],size[300010],H_son[300010],fa[300010];
ll tree[300010],Ans[300010];
int ti,x[100010],dfn[100010],n,deep[100010];
bool cmp(node x,node y)
{
return x.x<y.x;
}
void add(int u,int v)
{
next[++num]=head[u];
head[u]=num;
vet[num]=v;
}
void dfs(int u)
{
size[u]=1;
int Max=0,Maxs=0;
for (int i=head[u];i;i=next[i])
{
int v=vet[i];
if (v==fa[u]) continue;
dfs(v);
if (size[v]>Max) Max=size[v],Maxs=v;
size[u]+=size[v];
}
H_son[u]=Maxs;
}
void dfs(int u,int Top)
{
dfn[u]=++ti;
x[ti]=u;
top[u]=Top;
if (H_son[u])
dfs(H_son[u],Top);
for (int i=head[u];i;i=next[i])
{
int v=vet[i];
if (v!=H_son[u]&&v!=fa[u])
dfs(v,v);
}
}
void pushdown(int t,int l,int r)
{
if (!tag[t]) return;
int mid=(l+r)>>1;
tree[t<<1]+=(ll)tag[t]*(mid-l+1);
tree[t<<1|1]+=(ll)tag[t]*(r-mid);
tag[t<<1]+=tag[t];
tag[t<<1|1]+=tag[t];
tag[t]=0;
}
ll query(int l,int r,int x,int y,int t)
{
if (l==x&&y==r)
return tree[t];
pushdown(t,l,r);
int mid=(l+r)>>1;
if (y<=mid) return query(l,mid,x,y,t<<1);
else if (x>mid) return query(mid+1,r,x,y,t<<1|1);
else return query(l,mid,x,mid,t<<1)+query(mid+1,r,mid+1,y,t<<1|1);
}
void modify(int l,int r,int x,int y,int t,int key)
{
if (l==x&&y==r)
{
tag[t]+=key;
tree[t]+=(ll)key*(r-l+1);
return;
}
pushdown(t,l,r);
int mid=(l+r)>>1;
if (y<=mid) modify(l,mid,x,y,t<<1,key);
else if (x>mid) modify(mid+1,r,x,y,t<<1|1,key);
else modify(l,mid,x,mid,t<<1,key),modify(mid+1,r,mid+1,y,t<<1|1,key);
tree[t]=tree[t<<1]+tree[t<<1|1];
}
ll solve(int x)
{
ll ans=0;
while (x)
{
ans+=query(1,n,dfn[top[x]],dfn[x],1);
x=fa[top[x]];
}
return ans;
}
void Change(int x)
{
while (x)
{
modify(1,n,dfn[top[x]],dfn[x],1,1);
x=fa[top[x]];
}
}
int main()
{
int m;
scanf("%d%d",&n,&m);
for (int i=2;i<=n;i++)
{
int u;
scanf("%d",&u);
u++;
fa[i]=u;
add(u,i);
add(i,u);
}
dfs(1);
deep[1]=1;
dfs(1,1);
int cnt=0;
for (int i=1;i<=m;i++)
{
int L,R,Z;
scanf("%d%d%d",&L,&R,&Z);
L++,R++,Z++;
q[++cnt].x=L-1,q[cnt].z=Z,q[cnt].c=-1,q[cnt].id=i;
q[++cnt].x=R,q[cnt].z=Z,q[cnt].c=1,q[cnt].id=i;
}
sort(q+1,q+1+cnt,cmp);
for (int i=1;i<=q[1].x;i++)
Change(i);
Ans[q[1].id]+=solve(q[1].z)*(ll)q[1].c;
q[1].x=max(q[1].x,1);
for (int i=2;i<=cnt;i++)
{
for (int j=q[i-1].x+1;j<=q[i].x;j++)
Change(j);
Ans[q[i].id]+=solve(q[i].z)*(ll)q[i].c;
}
for (int i=1;i<=m;i++)
printf("%lld\n",Ans[i]%mo);
return 0;
}