题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3626
题目大意:
给出一个n个节点的有根树(编号为0到n-1,根节点为0),q个询问。求在[l,r]区间内的每个节点i与z的最近公共祖先的深度之和。
n,q<=5,0000 答案mod 201314
p.s.根的深度为1
========这是道好题 想不到再看(然而找题解的肯定都是跟我一样想不到的orz=========
【↑这个人是zz 别管= =
题解:
这个好题啊..然而想了好久之后滚去看大神博客了(/v \ )
---------------------------------
首先,如何通过路径操作求得x与y的lca的深度咧?
-先将x到根路径上的点的权值+1,然后询问y到根路径上点的权值和,这个权值和就是x与y的lca的深度√
而且非常好的一点就是,这个权值和是可以累加的。这是什么意思咧?
-比如询问是[1,3]跟4的,那么分别将1,2,3到根搞一次(这个时候权值是累加的啊= =),再查询4到根上点的权值和,就得到了[1,3]分别跟4的lca的深度的和了....(感觉好废话orz)
知道了这两个,就好做啦~
把询问离线后排序一下,依次搞搞就好了√
上代码 (忘了改回lld..PE了TAT)..
啊 真的 naive的我以为加了读入优化会快很多,然而、结果、并不会= =
那些1s-的是怎么跑的求告知!!!
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long LL;
#define mod 201314
#define maxn 50100
struct node
{
int x,y,c,next;
}a[maxn];
int len,first[maxn];
struct tree
{
int l,r,lc,rc;LL c,la;//c-权值 la-lazy标志
}tr[maxn*2];int trlen;
struct xw
{
int x,id,c;LL ans;
//id-存编号 最后搞原询问顺序时排序用的 x,c不造怎么描述看下面意会吧orz
}as[maxn*2];
int top[maxn],dep[maxn],son[maxn];
int z=0,ys[maxn],tot[maxn],fa[maxn];
bool cmp1(xw x,xw y) {return x.x<y.x;}
bool cmp2(xw x,xw y) {return x.id<y.id;}
int read()
{
char ch=getchar();
for (;ch>'9'||ch<'0';ch=getchar());
int tmp=0;
for (;'0'<=ch && ch<='9';ch=getchar())
tmp=tmp*10+int(ch)-48;
return tmp;
}
void ins(int x,int y)
{
len++;
a[len].x=x;a[len].y=y;
a[len].next=first[x];first[x]=len;
}
void dfs1(int x)
{
tot[x]=1;son[x]=0;
for (int k=first[x];k!=-1;k=a[k].next)
{
int y=a[k].y;
if (y!=fa[x])
{
dep[y]=dep[x]+1;
fa[y]=x;
dfs1(y);
if (tot[son[x]]<tot[y]) son[x]=y;
tot[x]+=tot[y];
}
}
}
void dfs2(int x,int tp)
{
ys[x]=++z;top[x]=tp;
if (son[x]!=0) dfs2(son[x],tp);
for (int k=first[x];k!=-1;k=a[k].next)
{
int y=a[k].y;
if (y!=fa[x] && y!=son[x])
dfs2(y,y);
}
}
void bt(int l,int r)
{
trlen++;int now=trlen;
tr[now].l=l;tr[now].r=r;
tr[now].lc=tr[now].rc=-1;
tr[now].c=tr[now].la=0;
if (l<r)
{
int mid=(l+r)>>1;
tr[now].lc=trlen+1;bt(l,mid);
tr[now].rc=trlen+1;bt(mid+1,r);
}
}
void updata(int now,int lc,int rc)
{
if (tr[now].la!=0)
{
int l=tr[lc].l,r=tr[lc].r;
tr[lc].c+=(r-l+1)*tr[now].la;
tr[lc].la+=tr[now].la;
l=tr[rc].l;r=tr[rc].r;
tr[rc].c+=(r-l+1)*tr[now].la;
tr[rc].la+=tr[now].la;
tr[now].la=0;
}
}
void change(int now,int l,int r)
{
if (tr[now].l==l && tr[now].r==r)
{
tr[now].c+=r-l+1;
tr[now].la++;
return;
}
int mid=(tr[now].l+tr[now].r)>>1,lc=tr[now].lc,rc=tr[now].rc;
updata(now,lc,rc);
if (r<=mid) change(lc,l,r);
else if (l>mid) change(rc,l,r);
else change(lc,l,mid),change(rc,mid+1,r);
tr[now].c=tr[lc].c+tr[rc].c;
}
int query(int now,int l,int r)
{
if (tr[now].l==l && tr[now].r==r) return tr[now].c;
int mid=(tr[now].l+tr[now].r)>>1,lc=tr[now].lc,rc=tr[now].rc;
updata(now,lc,rc);
if (r<=mid) return query(lc,l,r);
else if (l>mid) return query(rc,l,r);
else return query(lc,l,mid)+query(rc,mid+1,r);
}
void add(int x)
{
int tx=top[x];
while (x)
{
change(1,ys[tx],ys[x]);
x=fa[tx];tx=top[x];
}
}
int ask(int x)
{
int ans=0,tx=top[x];
while (x)
{
ans+=query(1,ys[tx],ys[x]);
x=fa[tx];tx=top[x];
}
return ans;
}
int main()
{
//freopen("a.in","r",stdin);
//freopen("a.out","w",stdout);
int n,m,i,x,y,l,r,c,k;
//scanf("%d%d",&n,&m);
n=read();m=read();
len=0;memset(first,-1,sizeof(first));
for (i=2;i<=n;i++)
{
//scanf("%d",&x);
x=read();
x++;ins(x,i);
}
dep[1]=1;fa[1]=0;dfs1(1);
z=0;dfs2(1,1);
trlen=0;bt(1,n);
for (i=1;i<=m;i++)
{
//scanf("%d%d%d",&x,&y,&c);
x=read();y=read();c=read();
x++;y++;c++;
as[i*2-1].x=x-1;as[i*2-1].id=i*2-1;as[i*2-1].c=c;
as[i*2].x=y;as[i*2].id=i*2;as[i*2].c=c;
}sort(as+1,as+m+m+1,cmp1);
for (k=1,i=0;i<=n;i++)
{
add(i);
for (;as[k].x==i;k++)
as[k].ans=ask(as[k].c);
}sort(as+1,as+m+m+1,cmp2);
for (i=1;i<=m;i++)
printf("%I64d\n",(as[i*2].ans-as[i*2-1].ans)%mod);
return 0;
}