传送门

考虑离线+差分。

lirdep[LCA(i,z)]\sum _{l \le i \le r} dep[LCA(i,z)]转化成1irdep[LCA(i,z)]1il1dep[LCA(i,z)]\sum _{1 \le i \le r} dep[LCA(i,z)]-\sum _{1 \le i \le l-1} dep[LCA(i,z)]

(代码里面下标整体+1,所以略有出入)

仔细观察,发现LCA(i,z)LCA(i,z)都在zz到根节点的路径上面,我们转化概念,dep[u]dep[u]其实上是uu上面节点的个数+1+1,于是我们有了思路:将ii到根节点路径上面节点全部+1,zz到根节点上面所有节点权值之和就是dep[LCA(i,z)]dep[LCA(i,z)]

这样有什么好处,首先,我们去掉了LCALCA,其次,这个东西可以树剖维护,因为它具有可加性。

于是实现非常简单,只要支持链+1,链求和即可。

#include <bits/stdc++.h>
#define MOD 201314
#define MAXN 50005
using namespace std;
inline int read(){
    int x=0,f=1;
    char ch=getchar();
    while (ch<'0'||ch>'9'){
        if (ch=='-') f=-1;
        ch=getchar();
    }
    while (ch>='0'&&ch<='9'){
        x=(x<<3)+(x<<1)+(ch^'0');
        ch=getchar();
    }
    return x*f;
}
vector<int>G[MAXN];
inline void AddEdge(int u,int v){
    G[u].push_back(v);
}
int sz[MAXN],big[MAXN],fa[MAXN],top[MAXN],dep[MAXN];
void dfs1(int u){
    sz[u]=1;
    for (register int i=0;i<G[u].size();++i){
        int v=G[u][i];
        if (v!=fa[u]){
            dep[v]=dep[u]+1;
            dfs1(v);
            sz[u]+=sz[v];
            if (sz[big[u]]<sz[v]) big[u]=v;
            
        }
    }
}
int seq[MAXN],cnt;
void dfs2(int u,int t){
    seq[u]=++cnt;
    top[u]=t;
    if (big[u]) dfs2(big[u],t);
    for (register int i=0;i<G[u].size();++i){
        int v=G[u][i];
        if (v!=fa[u]&&v!=big[u]){
            dfs2(v,v);
        }
    }
}
namespace SegmentTree{
    struct node{
        int l,r;
        int val,tag;
        inline int len(){return r-l+1;}
    }tree[MAXN<<2];
    #define lc i<<1
    #define rc i<<1|1
    inline void Change(int i,int v){
        tree[i].val=(tree[i].val+v*tree[i].len()%MOD)%MOD;
        tree[i].tag=(tree[i].tag+v)%MOD;
    }
    inline void pushdown(int i){
        if (tree[i].tag){
            Change(lc,tree[i].tag),Change(rc,tree[i].tag);
            tree[i].tag=0;
        }
    }
    inline void pushup(int i){
        tree[i].val=(tree[lc].val+tree[rc].val)%MOD;
    }
    void Build(int i,int l,int r){
        tree[i].l=l,tree[i].r=r;
        tree[i].val=tree[i].tag=0;
        if (l==r) return ;
        int mid=(l+r)>>1;
        Build(lc,l,mid);
        Build(rc,mid+1,r);
    }
    void Update(int i,int L,int R,int val){
        if (L<=tree[i].l&&tree[i].r<=R){
            Change(i,val);
            return ;
        }
        int mid=(tree[i].l+tree[i].r)>>1;
        pushdown(i);
        if (L<=mid) Update(lc,L,R,val);
        if (mid<R) Update(rc,L,R,val);
        pushup(i);
    }
    int Query(int i,int L,int R){
        if (L<=tree[i].l&&tree[i].r<=R){
            return tree[i].val;
        }
        int mid=(tree[i].l+tree[i].r)>>1,ans=0;
        pushdown(i);
        if (L<=mid) ans=(ans+Query(lc,L,R))%MOD;
        if (mid<R) ans=(ans+Query(rc,L,R))%MOD;
        return ans;
    }
}
using namespace SegmentTree;
inline void Update_Chain(int u,int v){
    while (top[u]!=top[v]){
        if (dep[top[u]]<dep[top[v]]){
            swap(u,v);
        }
        Update(1,seq[top[u]],seq[u],1);
        u=fa[top[u]];
    }
    if (dep[u]>dep[v]) swap(u,v);
    Update(1,seq[u],seq[v],1);
}
inline int Query_Chain(int u,int v){
    int ans=0;
    while (top[u]!=top[v]){
        if (dep[top[u]]<dep[top[v]]){
            swap(u,v);
        }
        ans=(ans+Query(1,seq[top[u]],seq[u]))%MOD;
        u=fa[top[u]];
    }
    if (dep[u]>dep[v]) swap(u,v);
    return (ans+Query(1,seq[u],seq[v]))%MOD;
}
int n;
inline void Init(){
    dep[1]=1;
    dfs1(1);
    dfs2(1,1);
    Build(1,1,n);
}
struct Q{
    int pos,flag,z,id;
}q[MAXN<<2];
int ans[MAXN];
inline bool operator < (const Q &A,const Q &B){
    return A.pos<B.pos;
}
int tot;
int main(){
    n=read();int m=read();
    for (register int i=2;i<=n;++i){
        int f=read()+1;
        fa[i]=f;
        AddEdge(f,i);
    }
    Init();
    for (register int i=1;i<=m;++i){
        int l=read(),r=read()+1,z=read()+1;
        q[++tot]=Q{l,-1,z,i};
        q[++tot]=Q{r,1,z,i};
    }
    sort(q+1,q+1+tot);
    int now=0;//现在加入到那个点
    for (register int i=1;i<=tot;++i){
        while (now<q[i].pos){
            Update_Chain(1,++now);
        }
        ans[q[i].id]+=Query_Chain(1,q[i].z)*q[i].flag;
    }
    for (register int i=1;i<=m;++i){
        printf("%d\n",(ans[i]+MOD)%MOD);
    }
}