帮助复习了树剖的基本操作。
需要考虑一下lca最近公共祖先的最原始的性质,这样就可以来用树剖加线段树维护了。
但是这样是个傻逼复杂度:O(n∗logn∗logn*q)(树剖加线段树,两个log),我们需要把q去掉,所以就离线做一遍,利用前缀和,差分一下即可。和gss2的离线思路差不多类似,可以算作一种套路吧。
吐槽:
一个晚上就做了一道题???我还是太菜了呀…
明明有时间的,但是做完一题整个人就痿了???…
#include <bits/stdc++.h>
using namespace std;
const int N=5e4+5,MOD=201314;
int n,m,u,l,r,z;
int size[N],d[N],f[N],son[N];
int tot,top[N],id[N];
int cnt,head[N];
struct edge{int from,next,to;}e[N<<1];
int sum[N<<2],tag[N<<2];
int summ,ans1[N],ans2[N];
struct number{int pos,s,id,f;}num[N<<1];
inline void add(int u,int v)
{
cnt++;
e[cnt].next=head[u];
e[cnt].from=u;
e[cnt].to=v;
head[u]=cnt;
}
void dfs(int u,int fa)
{
size[u]=1;
for (register int i=head[u]; i; i=e[i].next)
if (e[i].to!=fa)
{
d[e[i].to]=d[u]+1;
f[e[i].to]=u;
dfs(e[i].to,u);
size[u]+=size[e[i].to];
if (size[son[u]]<size[e[i].to]) son[u]=e[i].to;
}
}
void dfs2(int u,int TP)
{
tot++;
id[u]=tot;
top[u]=TP;
if (son[u]) dfs2(son[u],TP);
for (register int i=head[u]; i; i=e[i].next)
if (e[i].to!=f[u] && e[i].to!=son[u]) dfs2(e[i].to,e[i].to);
}
inline void pushdown(int k,int l,int r)
{
int mid=l+r>>1;
if (!tag[k]) return;
tag[k<<1]+=tag[k]; tag[k<<1|1]+=tag[k];
tag[k<<1]%=MOD; tag[k<<1|1]%=MOD;
sum[k<<1]+=(mid-l+1)*tag[k];
sum[k<<1|1]+=(r-(mid+1)+1)*tag[k];
sum[k<<1]%=MOD; sum[k<<1|1]%=MOD;
tag[k]=0;
}
void change(int k,int l,int r,int qx,int qy,int v)
{
if (qx<=l && r<=qy)
{
sum[k]+=(r-l+1)*v;
sum[k]%=MOD;
tag[k]+=v;
tag[k]%=MOD;
return;
}
pushdown(k,l,r);
int mid=l+r>>1;
if (qx<=mid) change(k<<1,l,mid,qx,qy,v);
if (mid<qy) change(k<<1|1,mid+1,r,qx,qy,v);
sum[k]=sum[k<<1]+sum[k<<1|1];
sum[k]%=MOD;
}
int query(int k,int l,int r,int qx,int qy)
{
if (qx<=l && r<=qy) return sum[k];
pushdown(k,l,r);
int mid=l+r>>1;
int ans=0;
if (qx<=mid) ans=(ans+query(k<<1,l,mid,qx,qy));
if (mid<qy) ans=(ans+query(k<<1|1,mid+1,r,qx,qy));
return ans;
}
inline void modify(int u,int v,int z)
{
while (top[u]!=top[v])
{
if (d[top[u]]<d[top[v]]) swap(u,v);
change(1,1,n,id[top[u]],id[u],z);
u=f[top[u]];
}
if (d[u]>d[v]) swap(u,v);
change(1,1,n,id[u],id[v],z);
}
inline int qsum(int u,int v)
{
int ans=0;
while (top[u]!=top[v])
{
if (d[top[u]]<d[top[v]]) swap(u,v);
ans=(ans+query(1,1,n,id[top[u]],id[u]))%MOD;
u=f[top[u]];
}
if (d[u]>d[v]) swap(u,v);
ans=(ans+query(1,1,n,id[u],id[v]))%MOD;
return ans;
}
inline bool cmp(number a,number b)
{
return a.pos<b.pos;
}
int main(){
scanf("%d%d",&n,&m);
for (register int i=2; i<=n; ++i)
{
scanf("%d",&u); u++;
add(u,i); add(i,u);
}
d[1]=1; f[1]=0;
dfs(1,0); dfs2(1,1);
for (register int i=1; i<=m; ++i)
{
scanf("%d%d%d",&l,&r,&z);
l++; r++; z++;
summ++;
num[summ].pos=l-1; num[summ].s=z; num[summ].id=i; num[summ].f=0;
summ++;
num[summ].pos=r; num[summ].s=z; num[summ].id=i; num[summ].f=1;
}
sort(num+1,num+summ+1,cmp);
int now=0;
for (register int i=1; i<=summ; ++i)
{
while (now<num[i].pos)
{
now++;
modify(1,now,1);
}
if (!num[i].f) ans1[num[i].id]=qsum(1,num[i].s);
else ans2[num[i].id]=qsum(1,num[i].s);
}
for (register int i=1; i<=m; ++i) printf("%d\n",(ans2[i]-ans1[i]+MOD)%MOD);
return 0;
}