[LNOI2014]LCA
考虑到\(dep\)等同于到根的点数。
考虑把\([l,r]\)的点到根节点都打上1的标记,再查询\(z\)到根的权值即可。
考虑如何不重的统计。
那么就进行前缀和,并且从小到大加入,然后拆开一个询问的操作就可以。
树剖加线段树,\(O(nlog^2n)\)。
#include<iostream>
#include<cstdio>
#include<algorithm>
#define ll long long
#define N 500005
#define mod 201314
ll n,m;
ll cnt,head[N];
struct P{
int to,next;
}e[N << 2];
inline void add(int x,int y){
e[++cnt].to = y;
e[cnt].next = head[x];
head[x] = cnt;
}
ll son[N],siz[N],fa[N],dep[N],top[N],dfn[N];
inline void dfs(int u,int f){
dep[u] = dep[f] + 1;
fa[u] = f;
siz[u] = 1;
for(int i = head[u];i;i = e[i].next){
int v = e[i].to;
if(v == f)
continue;
dfs(v,u);
siz[u] += siz[v];
if(siz[v] > siz[son[u]])
son[u] = v;
}
}
ll dfncnt;
inline void dfs2(int u,int t){
top[u] = t;
dfn[u] = ++dfncnt;
if(son[u])dfs2(son[u],t);
for(int i = head[u];i;i = e[i].next){
int v = e[i].to;
if(v == fa[u] || v == son[u] || v == 1)
continue;
dfs2(v,v);
}
}
//tree_cut__________
ll s[N << 2],tag[N << 2];
#define ls(x) (x << 1)
#define rs(x) (x << 1 | 1)
#define mid ((l + r) >> 1)
inline void up(int u){
s[u] = (s[ls(u)] + s[rs(u)]) % mod;
}
inline void down(int u,int l,int r){
if(tag[u]){
tag[ls(u)] += tag[u];
s[ls(u)] += tag[u] * (mid - l + 1);
s[ls(u)] %= mod;
tag[rs(u)] += tag[u];
s[rs(u)] += tag[u] * (r - mid);
s[rs(u)] %= mod;
tag[u] = 0;
}
}
inline void change(int u,int l,int r,int tl,int tr,int p){
// std::cout<<u<<" "<<l<<" "<<r<<" "<<tl<<" "<<tr<<" "<<p<<std::endl;
if(tl <= l && r <= tr){
tag[u] += p;
s[u] += p * (r - l + 1);
s[u] %= mod;
return ;
}
down(u,l,r);
if(tl <= mid)
change(ls(u),l,mid,tl,tr,p);
if(tr > mid)
change(rs(u),mid + 1,r,tl,tr,p);
up(u);
}
inline ll qi(int u,int l,int r,int tl,int tr){
ll ans = 0;
// std::cout<<l<<" "<<r<<" "<<tl<<" "<<tr<<" "<<s[u]<<std::endl;
if(tl <= l && r <= tr)
return s[u];
down(u,l,r);
if(tl <= mid)
ans += qi(ls(u),l,mid,tl,tr),ans %= mod;
if(tr > mid)
ans += qi(rs(u),mid + 1,r,tl,tr),ans %= mod;
return ans;
}
//______________________
ll qcnt;
struct d{
ll in,opt,id;
}q[N];
bool operator < (d a,d b){
return a.in < b.in;
}
ll final[N],ans[N];
ll tp;
inline void add(int x){
// std::cout<<"add"<<x<<":"<<std::endl;
while(dfn[top[x]] != dfn[1]){
change(1,1,n,dfn[top[x]],dfn[x],1);
// std::cout<<dfn[top[x]]<<" "<<dfn[x]<<std::endl;
x = fa[top[x]];
}
change(1,1,n,dfn[1],dfn[x],1);
// std::cout<<dfn[1]<<" "<<dfn[x]<<std::endl;
}
inline void deal(int p){
// std::cout<<"deal"<<p<<":"<<std::endl;
int x = final[q[p].id];
ll f = 0;
while(dfn[top[x]] != dfn[1]){
f += qi(1,1,n,dfn[top[x]],dfn[x]);
// std::cout<<dfn[top[x]]<<" "<<dfn[x]<<" "<<f<<std::endl;
x = fa[top[x]];
}
f += qi(1,1,n,dfn[1],dfn[x]);
// std::cout<<dfn[1]<<" "<<dfn[x]<<" "<<f<<std::endl;
ans[q[p].id] = (ans[q[p].id] + q[p].opt * f + mod) % mod;
}
int main(){
scanf("%lld%lld",&n,&m);
for(int i = 2;i <= n;++i){
ll x;
scanf("%lld",&x);
x ++ ;
add(i,x);
add(x,i);
}
dfs(1,0);
dfs2(1,1);
// for(int i = 1;i <= n;++i){
// std::cout<<dfn[i]<<" "<<son[i]<<std::endl;
// }
for(int i = 1;i <= m;++i){
ll l,r,z;
scanf("%lld%lld%lld",&l,&r,&z);
l ++ ;
r ++ ;
z ++ ;
l -- ;
q[++qcnt].id = i;
q[qcnt].in = l;
q[qcnt].opt = -1;
q[++qcnt].id = i;
q[qcnt].in = r;
q[qcnt].opt = 1;
final[i] = z;
}
std::sort(q + 1,q + qcnt + 1);
// for(int i = 1;i <= qcnt;++i){
// std::cout<<q[i].in<<" "<<q[i].id<<" "<<q[i].opt<<std::endl;
// }
tp = 1;
while(q[tp].in == 0){
deal(tp);
tp ++ ;
}
for(int i = 1;i <= n;++i){
add(i);
while(q[tp].in == i){
deal(tp);
tp ++ ;
}
}
for(int i = 1;i <= m;++i)
std::cout<<ans[i]<<std::endl;
}