給出一個n個節點的有根樹(編號爲0到n-1,根節點爲0)。一個點的深度定義爲這個節點到根的距離+1。
設dep[i]表示點i的深度,LCA(i,j)表示i與j的最近公共祖先。
有q次詢問,每次詢問給出l r z,求sigma_{l<=i<=r}dep[LCA(i,z)]。
(即,求在[l,r]區間內的每個節點i與z的最近公共祖先的深度之和)
n,q<=50000
對於a和b,如果我們要求dep[LCA(a,b)],我們可以換一個求法:將a到根的路徑上所有點權值+1,則b到根路徑上所有點權值和就是dep[LCA(a,b)]。有了這個求法後我們就可以將詢問離線,將一個詢問拆成[0,r]對於z的貢獻-[0,l-1]對於z的貢獻,分別掛在r和l-1上,從0到n-1依次將每個節點到根路徑+1並查詢出掛在這個點上的詢問即可。
答案要取模,注意負數要加回來。
#include<cstdio>
#define gm 50001
using namespace std;
typedef unsigned long long ll;
struct node
{
node *s[2],*f;
size_t add,sz,v;
ll sum;
node();
inline char r(){return this==f->s[0]?0:this==f->s[1]?1:-1;}
inline void up(){sz=s[0]->sz+1+s[1]->sz,sum=s[0]->sum+v+s[1]->sum;}
inline void plus(size_t);
inline void down()
{
if(~r()) f->down();
if(add)
{
s[0]->plus(add);
s[1]->plus(add);
add=0;
}
}
}tr[gm],*nil=tr+50000;
node::node():f(tr+50000),add(),sz(1),sum(){s[0]=s[1]=tr+50000;}
inline void node::plus(size_t x=1)
{
if(this!=nil)
sum+=ll(sz)*x,add+=x,v+=x;
}
inline void rot(node *x)
{
static node *o,*y;
static char k;
k=x->r();if(k==-1) return;
k=!k;
o=x->f,y=x->s[k];
x->s[k]=o,o->s[!k]=y;
if(~(k=o->r())) o->f->s[k]=x;
x->f=o->f,o->f=x,y->f=o;
o->up();
}
inline void splay(node *x)
{
x->down();
while(~x->r()) rot(x->f->r()==x->r()?x->f:x),rot(x);
x->up();
}
inline void access(node *x)
{
static node *y,*z;
y=nil;z=x;
while(x!=nil)
{
splay(x);
x->s[1]=y;
x->up();
y=x;
x=x->f;
}
splay(z);
}
inline void plus(node *x)
{
access(x);
x->plus();
}
inline int count(node *x)
{
access(x);
return x->sum%201314;
}
int n,q;
int ans[gm];
struct query
{
bool plus;
int no,z;
query *n;
query(int no,int z,bool plus,query *n):
no(no),z(z),plus(plus),n(n){}
}*f[gm];
int main()
{
scanf("%d%d",&n,&q);
nil->sz=0;
for(int i=1,fa;i<n;++i)
{
scanf("%d",&fa);
tr[i].f=tr+fa;
}
for(int i=1,l,r,z;i<=q;++i)
{
scanf("%d%d%d",&l,&r,&z);
if(l) f[l-1]=new query(i,z,0,f[l-1]);
f[r]=new query(i,z,1,f[r]);
}
for(int i=0;i<n;++i)
{
plus(tr+i);
for(query *j=f[i];j;j=j->n)
{
int res=count(tr+j->z);
if(j->plus) ans[j->no]+=res;
else ans[j->no]-=res;
}
}
for(int i=1;i<=q;++i)
{
if(ans[i]<0) ans[i]+=201314;
printf("%d\n",ans[i]);
}
return 0;
}