【BZOJ3626】[LNOI2014]LCA
Description
给出一个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的最近公共祖先的深度之和)
Input
第一行2个整数n q。
接下来n-1行,分别表示点1到点n-1的父节点编号。
接下来q行,每行3个整数l r z。
Output
输出q行,每行表示一个询问的答案。每个答案对201314取模输出
Sample Input
5 2
0
0
1
1
1 4 3
1 4 2
0
0
1
1
1 4 3
1 4 2
Sample Output
8
5
5
HINT
共5组数据,n与q的规模分别为10000,20000,30000,40000,50000。
题解:考虑dep[lca(a,b)]可以表示成什么,我们将a到根路径上的每个节点的权值都+1,然后查询b到根的路径上的所有点的权值和即可。
发现这个东西是可以用前缀和来搞的。我们将询问拆成前缀相减的形式,从1到n枚举i,将i到根路径上所有点的权值和+1,顺便处理当前的所有询问即可。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define mod 201314
#define lson x<<1
#define rson x<<1|1
using namespace std;
const int maxn=50010;
int n,m,sum,tot,cnt;
int to[maxn],next[maxn],head[maxn],deep[maxn],siz[maxn],fa[maxn],top[maxn],son[maxn],p[maxn];
int s[maxn<<2],t[maxn<<2],ans[maxn];
struct QUERY
{
int qx,org,k,qz;
}q[maxn<<1];
inline int rd()
{
int ret=0; char gc=getchar();
while(gc<'0'||gc>'9') gc=getchar();
while(gc>='0'&&gc<='9') ret=(ret<<3)+(ret<<1)+gc-'0',gc=getchar();
return ret;
}
bool cmp(QUERY a,QUERY b)
{
return a.qx<b.qx;
}
void dfs1(int x)
{
siz[x]=1;
for(int i=head[x];i!=-1;i=next[i])
{
deep[to[i]]=deep[x]+1;
dfs1(to[i]);
siz[x]+=siz[to[i]];
if(siz[to[i]]>siz[son[x]]) son[x]=to[i];
}
}
void dfs2(int x,int tp)
{
top[x]=tp,p[x]=++tot;
if(son[x]) dfs2(son[x],tp);
for(int i=head[x];i!=-1;i=next[i]) if(to[i]!=son[x]) dfs2(to[i],to[i]);
}
void pushdown(int l,int r,int x)
{
if(t[x])
{
int mid=(l+r)>>1;
s[lson]=(s[lson]+(mid-l+1)*t[x])%mod;
s[rson]=(s[rson]+(r-mid)*t[x])%mod;
t[lson]+=t[x],t[rson]+=t[x],t[x]=0;
}
}
void updata(int l,int r,int x,int a,int b)
{
if(a<=l&&r<=b)
{
s[x]+=r-l+1,t[x]++;
return ;
}
pushdown(l,r,x);
int mid=(l+r)>>1;
if(a<=mid) updata(l,mid,lson,a,b);
if(b>mid) updata(mid+1,r,rson,a,b);
s[x]=(s[lson]+s[rson])%mod;
}
int query(int l,int r,int x,int a,int b)
{
if(a<=l&&r<=b) return s[x];
pushdown(l,r,x);
int mid=(l+r)>>1;
if(b<=mid) return query(l,mid,lson,a,b);
if(a>mid) return query(mid+1,r,rson,a,b);
return query(l,mid,lson,a,b)+query(mid+1,r,rson,a,b);
}
void insert(int x)
{
while(x) updata(1,n,1,p[top[x]],p[x]),x=fa[top[x]];
}
int getsum(int x)
{
int ret=0;
while(x) ret=(ret+query(1,n,1,p[top[x]],p[x]))%mod,x=fa[top[x]];
return ret;
}
void add(int a,int b)
{
to[cnt]=b,next[cnt]=head[a],head[a]=cnt++;
}
int main()
{
n=rd(),m=rd();
int i,j;
memset(head,-1,sizeof(head));
for(i=2;i<=n;i++) fa[i]=rd()+1,add(fa[i],i);
deep[1]=1;
dfs1(1),dfs2(1,1);
for(i=1;i<=m;i++)
{
q[i*2-1].qx=rd(),q[i*2].qx=rd()+1;
q[i*2-1].qz=q[i*2].qz=rd()+1;
q[i*2-1].k=-1,q[i*2].k=1;
q[i*2-1].org=q[i*2].org=i;
}
sort(q+1,q+2*m+1,cmp);
for(i=1;i<=2*m;i++)
{
for(j=q[i-1].qx+1;j<=q[i].qx;j++) insert(j);
ans[q[i].org]+=q[i].k*getsum(q[i].qz);
}
for(i=1;i<=m;i++) printf("%d\n",(ans[i]+mod)%mod);
return 0;
}