题目描述
给出一个n个节点的有根树(编号为0到n-1,根节点为0)。一个点的深度定义为这个节点到根的距离+1。 设dep[i]表示点i的深度,LCA(i,j)表示i与j的最近公共祖先。 有q次询问,每次询问给出l r z,求
输入输出格式
输入格式:
第一行2个整数n q。 接下来n-1行,分别表示点1到点n-1的父节点编号。 接下来q行,每行3个整数l r z。
输出格式:
输出q行,每行表示一个询问的答案。每个答案对201314取模输出
输入输出样例
输入样例#1:
5 2
0
0
1
1
1 4 3
1 4 2
输出样例#1:
8
5
说明
共5组数据,n与q的规模分别为10000,20000,30000,40000,50000。
分析:
之前做过一道差不多的题目,是差分做的。
我们可以把从根到
路径上的点权都加
,然后从编号为
到
的节点往根走,这些路径的权值和即为所求。
然后我们可以换一种想法,把
到
上到根每一条路径点权都加1,求
到根路径权值和。
所以我们可以把询问离线,并拆成询问
在
这些边上的权值和减去
上的权值和。
然后我们一次插入编号为
的点的路径,然后解决
的询问,然后最后合并答案即可。
路径修改+路径查询可以用树链剖分解决,时间复杂度为 ,记得取模。
代码:
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#define LL long long
const LL mod=201314;
const LL maxn=100007;
using namespace std;
LL n,test,x,y,z,cnt;
LL ls[maxn];
LL dfn[maxn],top[maxn],size[maxn],dep[maxn],fa[maxn];
struct edge{
LL y,next;
}g[maxn*2];
struct rec{
LL x,l,num;
LL ans;
}q[maxn*2];
struct node{
LL sum,lazy;
}t[maxn*2];
bool cmp1(rec x,rec y)
{
return x.l<y.l;
}
bool cmp2(rec x,rec y)
{
return x.num<y.num;
}
void add(LL x,LL y)
{
g[++cnt]=(edge){y,ls[x]};
ls[x]=cnt;
}
void dfs1(LL x,LL f)
{
size[x]=1;
dep[x]=dep[f]+1;
fa[x]=f;
for (LL i=ls[x];i>0;i=g[i].next)
{
LL y=g[i].y;
if (y!=fa[x])
{
dfs1(y,x);
size[x]+=size[y];
}
}
}
void dfs2(LL x,LL f)
{
top[x]=f;
dfn[x]=++cnt;
LL c=maxn-1;
for (LL i=ls[x];i>0;i=g[i].next)
{
LL y=g[i].y;
if (y==fa[x]) continue;
if (size[y]>size[c]) c=y;
}
if (c==maxn-1) return;
dfs2(c,f);
for (LL i=ls[x];i>0;i=g[i].next)
{
LL y=g[i].y;
if ((y==fa[x]) || (y==c)) continue;
dfs2(y,y);
}
}
void ins(LL p,LL l,LL r,LL x,LL y,LL k)
{
if ((l==x) && (r==y))
{
t[p].lazy=(t[p].lazy+k)%mod;
t[p].sum=(t[p].sum+(r-l+1)*k)%mod;
return;
}
LL mid=(l+r)/2;
if (t[p].lazy)
{
t[p*2].lazy=(t[p*2].lazy+t[p].lazy)%mod;
t[p*2+1].lazy=(t[p*2+1].lazy+t[p].lazy)%mod;
t[p*2].sum=(t[p*2].sum+(mid-l+1)*1ll*t[p].lazy)%mod;
t[p*2+1].sum=(t[p*2+1].sum+(r-mid)*1ll*t[p].lazy)%mod;
t[p].lazy=0;
}
if (y<=mid) ins(p*2,l,mid,x,y,k);
else if (x>mid) ins(p*2+1,mid+1,r,x,y,k);
else
{
ins(p*2,l,mid,x,mid,k);
ins(p*2+1,mid+1,r,mid+1,y,k);
}
t[p].sum=(t[p*2].sum+t[p*2+1].sum)%mod;
}
LL getsum(LL p,LL l,LL r,LL x,LL y)
{
if ((l==x) && (r==y)) return t[p].sum;
LL mid=(l+r)/2;
if (t[p].lazy)
{
t[p*2].lazy=(t[p*2].lazy+t[p].lazy)%mod;
t[p*2+1].lazy=(t[p*2+1].lazy+t[p].lazy)%mod;
t[p*2].sum=(t[p*2].sum+(mid-l+1)*1ll*t[p].lazy)%mod;
t[p*2+1].sum=(t[p*2+1].sum+(r-mid)*1ll*t[p].lazy)%mod;
t[p].lazy=0;
}
if (y<=mid) return getsum(p*2,l,mid,x,y);
else if (x>mid) return getsum(p*2+1,mid+1,r,x,y);
else return (getsum(p*2,l,mid,x,mid)+getsum(p*2+1,mid+1,r,mid+1,y))%mod;
}
LL ask(LL x,LL y)
{
LL ans=0;
while (top[x]!=top[y])
{
if (dep[top[x]]>dep[top[y]]) swap(x,y);
ans=(ans+getsum(1,1,n,dfn[top[y]],dfn[y]))%mod;
y=fa[top[y]];
}
if (dep[x]>dep[y]) swap(x,y);
ans=(ans+getsum(1,1,n,dfn[x],dfn[y]))%mod;
return ans;
}
void change(LL x,LL y)
{
while (top[x]!=top[y])
{
if (dep[top[x]]>dep[top[y]]) swap(x,y);
ins(1,1,n,dfn[top[y]],dfn[y],1);
y=fa[top[y]];
}
if (dep[x]>dep[y]) swap(x,y);
ins(1,1,n,dfn[x],dfn[y],1);
}
int main()
{
scanf("%lld%lld",&n,&test);
for (LL i=1;i<n;i++)
{
scanf("%lld",&x);
add(x,i);
add(i,x);
}
for (LL i=1;i<=test;i++)
{
scanf("%lld%lld%lld",&x,&y,&z);
q[i*2-1]=(rec){z,x-1,i*2-1};
q[i*2]=(rec){z,y,i*2};
}
sort(q+1,q+2*test+1,cmp1);
dfs1(0,0);
cnt=0;
dfs2(0,0);
LL j=-1;
for (LL i=1;i<=test*2;i++)
{
while (j<q[i].l)
{
j++;
change(0,j);
}
if (q[i].l==-1) q[i].ans=0;
else q[i].ans=ask(0,q[i].x);
}
sort(q+1,q+2*test+1,cmp2);
for (LL i=1;i<=test;i++)
{
printf("%lld\n",(q[i*2].ans+mod-q[i*2-1].ans)%mod);
}
}