• 题意
  • 有一个很巧妙的转化:求x,y的dep[lca(x,y)]可以先x到根的路径上加1,然后查询y到根路径上的和。
    所以x->[l,r]的lca和,可以转化为,先把[l,r]中每个到根的路径+1,再求一次x到根的前缀和。
    然后[l,r]这种显然可以差分为两个询问[1..r]和[1..l-1],因此先把询问离线,用树链剖分维护区间加和求和,从前到后枚举每个前缀,每次修改+更新这个前缀的询问。具体见code
  • code:
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+5;
typedef long long ll;
int ls[N],ed[N],rs[N],Tcnt,rt[N],fa[N],nxt[N],to[N],head[N],ecnt,b[N];
int Time,dfn[N],sz[N],son[N],top[N];
ll ans[N];
void add_edge(int u,int v) {nxt[++ecnt]=head[u];to[ecnt]=v;head[u]=ecnt;}
struct query {int opt,x,id;};
vector<query> V[N];
void gt_son(int u) {
	sz[u]=1;
	for(int i=head[u];i;i=nxt[i]) {
		int v(to[i]);
		gt_son(v);sz[u]+=sz[v];
		if(sz[son[u]]<sz[v])son[u]=v;
	}
}
void gt_top(int u,int Tp) {
	top[u]=Tp;ed[Tp]=u;dfn[u]=++Time;b[Time]=u;
	if(son[u])gt_top(son[u],Tp);
	for(int i=head[u];i;i=nxt[i]) {
		int v(to[i]);if(v==son[u])continue;
		gt_top(v,v);
	}
}
struct seg {int l,r,len;ll cnt,lazy;}T[N];
void P_up(int x) {T[x].cnt=(T[ls[x]].cnt+T[rs[x]].cnt);}
void P_dw(int x) {
	if(!T[x].lazy)return;ll ad=T[x].lazy;T[x].lazy=0;
	T[ls[x]].cnt+=ad*T[ls[x]].len;T[ls[x]].lazy+=ad;T[rs[x]].cnt+=ad*T[rs[x]].len,T[rs[x]].lazy+=ad;
}
void Build(int &x,int l,int r) {
	x=++Tcnt;T[x]=(seg){l,r,r-l+1,0};
	if(l==r)return;
	int mid=(l+r)>>1;
	Build(ls[x],l,mid),Build(rs[x],mid+1,r);
}

void Update(int x,int l,int r,int w) {
	if(l<=T[x].l&&T[x].r<=r) {T[x].cnt+=w*T[x].len;T[x].lazy+=w;return;}
	P_dw(x);
	int mid=(T[x].l+T[x].r)>>1;
	if(l<=mid)Update(ls[x],l,r,w);
	if(r>mid)Update(rs[x],l,r,w);
	P_up(x);
}
ll Sum(int x,int l,int r) {
	if(l<=T[x].l&&T[x].r<=r) return T[x].cnt;
	P_dw(x);
	int mid=(T[x].l+T[x].r)>>1;ll res=0;
	if(l<=mid)res+=Sum(ls[x],l,r);
	if(r>mid)res+=Sum(rs[x],l,r);
	return res;
}
ll Ask(int v) {
	ll res=0;
	while(v) {
		int u=top[v];res+=Sum(rt[u],dfn[u],dfn[v]);v=fa[u];
	}
	return res;
}
void Update(int v) {
	while(v) {
		int u=top[v];Update(rt[u],dfn[u],dfn[v],1);v=fa[u];
	}
}
int main() {
	int n,m;scanf("%d%d",&n,&m);
	for(int i=2;i<=n;i++) {scanf("%d",&fa[i]);fa[i]++;add_edge(fa[i],i);}
	gt_son(1);
	gt_top(1,1);
	for(int i=1;i<=n;i++) {
		int j=dfn[ed[b[i]]];
		Build(rt[b[i]],i,j);i=j;
	}
	for(int i=1;i<=m;i++) {
		int l,r,x;scanf("%d%d%d",&l,&r,&x);
		l++;r++;x++;
		if(l>1)V[l-1].push_back((query){-1,x,i});
		V[r].push_back((query){1,x,i});
	}
	for(int i=1;i<=n;i++) {
		Update(i);
//		printf("!%d:\n",i);
		for(int j=0;j<V[i].size();j++) {
			query p=V[i][j];
			ans[p.id]+=p.opt*Ask(p.x);
		}
	}
	for(int i=1;i<=m;i++) printf("%lld\n",ans[i]%201314);
	return 0;
}