BZOJ
就是给定询问l,r,z求 ∑ri=ldeep(lca(i,z)) ∑ i = l r d e e p ( l c a ( i , z ) )
我们考虑把deep的含义转化一下,它就是表示某个点到根节点需要经过几个节点
那么把路径上的deep差分之后就变成了一条1,然后我们做一个区间询问和即可得到deep
那么我们就用这种思想,把[l,r]区间内所有点到rt的路径权值+1,再统计z到rt的权值和即为答案。可以 O(qnlogn) O ( q n log n ) 做到
但是q太大了,我们会想要优化掉它,考虑到我们可以把[l,r]转化为[1,l-1]和[1,r]的询问答案,那么我们就可以把询问拆开,然后排序,再依次把贡献算出来。即可
时间复杂度 O((n+q)logn) O ( ( n + q ) log n )
#include
#include
#define pushup(x) sum[x]=pls(val[x],pls(sum[ch[x][0]],sum[ch[x][1]])),sz[x]=sz[ch[x][0]]+sz[ch[x][1]]+1
#define pd(x) if(rev[x]||add[x])pushdown(x)
#define rg register
using namespace std;
typedef unsigned int ll;
const int maxn=50010,mod=201314;
struct query{
int pos,z,pls,id;
bool operator < (const query &x)const
{
if(pos==x.pos) return zreturn pos1];
template <typename Tp> inline void read(Tp &x)
{
x=0;int f=0;char ch=getchar();
while(ch<'0'||ch>'9') ch=getchar();
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
}
int n,m,top,p,stk[maxn],ans[maxn];
int f[maxn],ch[maxn][2],val[maxn],sz[maxn],rev[maxn],sum[maxn],add[maxn];
inline int pls(int x,int y){return x+y>=mod?x+y-mod:x+y;}
inline int dec(int x,int y){return x-y<0?x-y+mod:x-y;}
void addtag(int x,int v)
{
val[x]=pls(val[x],v);add[x]=pls(add[x],v);
sum[x]=pls(sum[x],(ll)v*sz[x]%mod);
}
inline bool isroot(int x){return ch[f[x]][0]!=x&&ch[f[x]][1]!=x;}
void pushdown(int x)
{
if(add[x])
{
if(ch[x][0]) addtag(ch[x][0],add[x]);
if(ch[x][1]) addtag(ch[x][1],add[x]);
add[x]=0;
}
if(rev[x])
{
rev[ch[x][0]]^=1;rev[ch[x][1]]^=1;
rev[x]=0;swap(ch[x][0],ch[x][1]);
}
}
void rotate(int x)
{
int fa=f[x],ff=f[fa],l,r;
if(ch[fa][0]==x) l=0;
else l=1;r=l^1;
if(!isroot(fa)) {if(ch[ff][0]==fa) ch[ff][0]=x;else ch[ff][1]=x;}
f[x]=ff;f[fa]=x;f[ch[x][r]]=fa;
ch[fa][l]=ch[x][r];ch[x][r]=fa;
pushup(fa);pushup(x);
}
void splay(int x)
{
stk[top=1]=x;
for(int i=x;!isroot(i);i=f[i]) stk[++top]=f[i];
for(int i=top;i;i--) pd(stk[i]);
while(!isroot(x))
{
int fa=f[x],ff=f[fa];
if(!isroot(fa))
{
if((ch[fa][0]==x)^(ch[ff][0]==fa)) rotate(x);
else rotate(fa);
}
rotate(x);
}
}
void access(int x){for(int t=0;x;t=x,x=f[x]) splay(x),ch[x][1]=t,pushup(x);}
void makeroot(int x){access(x);splay(x);rev[x]^=1;}
int find(int x){access(x);splay(x);while(ch[x][0]) x=ch[x][0];return x;}
void split(int x,int y){makeroot(x);access(y);splay(y);}
void cut(int x,int y){split(x,y);if(ch[y][0]==x) ch[y][0]=0,f[x]=0;}
void link(int x,int y){makeroot(x);f[x]=y;}
void input()
{
int x,l,r;
read(n);read(m);
for(rg int i=1;i<=n;i++) sz[i]=1;
for(rg int i=2;i<=n;i++){read(x);link(++x,i);}
for(rg int i=1;i<=m;i++)
{
read(l);read(r);read(a[i].z);a[i].z++;l++;r++;
a[i].pos=l-1;a[i].pls=0;
a[i+m].pos=r;a[i+m].pls=1;a[i+m].z=a[i].z;
a[i].id=a[i+m].id=i;
}
sort(a+1,a+m+m+1);
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
#endif
input();
while(a[p].pos<1) p++;
for(rg int i=1;i<=n;i++)
{
split(1,i);addtag(i,1);
while(a[p].pos<=i&&p<=m+m)
{
if(a[p].z!=a[p-1].z||a[p].pos!=a[p-1].pos) split(1,a[p].z);
if(a[p].pls) ans[a[p].id]=pls(ans[a[p].id],sum[a[p].z]);
else ans[a[p].id]=dec(ans[a[p].id],sum[a[p].z]);
p++;
}
}
for(rg int i=1;i<=m;i++) printf("%d\n",ans[i]);
return 0;
}