一个节点的深度,就是这个节点到根的路径上的节点数,所以所求可转化为 l 到 r 区间内每个节点到根与 z 到根的公共路径上点数之和。修改和查询的路径一定是某节点到根,用树链剖分来维护。
但每次都从 l 到 r 添加贡献再还原肯定不可行。我们能发现不同询问区间可能有重叠,似乎可以离线做;维护的又是公共点数的和,是可减的,能用差分求出。所以最终只要按顺序把节点 i 到根的值都+1,然后遇到询问就查询一下该点到根的值之和,根据是1 -- l-1的区间还是1 -- r的区间判断是加还是减就好了。记得保存询问的数组要开2倍。
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const int N=50010;
const ll mod=201314;
struct edge{
int y,next;
}data[N];
struct qry{
int x,y,tp,id;
}b1[N*2];
struct node{
ll x;
int f,siz;
}tree[N*4];
int n,q,num,num1,h[N],dep[N],faz[N],siz[N],son[N],tid[N],top[N];
ll ans[N];
inline int read(){
int x=0,f=0;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return f?-x:x;
}
inline void addedge(int x,int y){
data[++num].y=y;data[num].next=h[x];h[x]=num;
}
void dfs1(int u,int fa,int d){
dep[u]=d;faz[u]=fa;siz[u]=1;son[u]=0;
for(int i=h[u];i!=-1;i=data[i].next){
int v=data[i].y;
if(v!=fa){
dfs1(v,u,d+1);
siz[u]+=siz[v];
if(siz[v]>siz[son[u]])son[u]=v;
}
}
}
void dfs2(int u,int fa,int t){
tid[u]=++num1;top[u]=t;
if(son[u]==0)return;
dfs2(son[u],u,t);
for(int i=h[u];i!=-1;i=data[i].next){
int v=data[i].y;
if(v!=fa&&v!=son[u])dfs2(v,u,v);
}
}
bool cmp(qry i,qry j){
return i.x<j.x;
}
inline void update(int p){
tree[p].x=(tree[p<<1].x+tree[p<<1|1].x)%mod;
}
inline void new1(int p,int f){
tree[p].x=(tree[p].x+(1ll*f*tree[p].siz)%mod)%mod;
tree[p].f=(tree[p].f+f)%mod;
}
inline void pushdown(int p){
if(tree[p].f){
new1(p<<1,tree[p].f);new1(p<<1|1,tree[p].f);
tree[p].f=0;
}
}
void build(int p,int a,int b){
tree[p].siz=b-a+1;tree[p].x=tree[p].f=0;
if(a==b)return;
int mid=(a+b)>>1;
build(p<<1,a,mid);build(p<<1|1,mid+1,b);
}
void add(int p,int pa,int pb,int a,int b,int f){
if(a<=pa&&pb<=b){new1(p,f);return;}
pushdown(p);
int mid=(pa+pb)>>1;
if(a<=mid)add(p<<1,pa,mid,a,b,f);
if(mid<b)add(p<<1|1,mid+1,pb,a,b,f);
update(p);
}
ll query(int p,int pa,int pb,int a,int b){
if(a<=pa&&pb<=b)return tree[p].x;
pushdown(p);
int mid=(pa+pb)>>1;
ll q1=0,q2=0;
if(a<=mid)q1=query(p<<1,pa,mid,a,b);
if(mid<b)q2=query(p<<1|1,mid+1,pb,a,b);
update(p);
return (q1+q2)%mod;
}
inline void lca_add(int x){
for(;x;x=faz[top[x]])add(1,1,n,tid[top[x]],tid[x],1);
}
inline ll lca_query(int x){
ll ans1=0;
for(;x;x=faz[top[x]])ans1=(ans1+query(1,1,n,tid[top[x]],tid[x]))%mod;
return ans1;
}
int main(){
n=read();q=read();
num=0;memset(h,-1,sizeof h);
for(int x,i=2;i<=n;i++){x=read()+1;addedge(x,i);}
num1=0;dfs1(1,0,1);dfs2(1,0,1);
for(int l,r,z,cnt=0,i=1;i<=q;i++){
l=read()+1;r=read()+1;z=read()+1;
b1[++cnt].x=l-1;b1[cnt].y=z;b1[cnt].id=i;b1[cnt].tp=0;
b1[++cnt].x=r;b1[cnt].y=z;b1[cnt].id=i;b1[cnt].tp=1;
}
build(1,1,n);
sort(b1+1,b1+q*2+1,cmp);
for(int now=0,i=1;i<=2*q;i++){
while(now<b1[i].x){now++;lca_add(now);}
if(b1[i].tp==0)ans[b1[i].id]-=lca_query(b1[i].y);
else ans[b1[i].id]+=lca_query(b1[i].y);
}
for(int i=1;i<=q;i++)printf("%lld\n",(ans[i]+mod)%mod);
return 0;
}