题目描述
给出一个n个节点的有根树(编号为0到n-1,根节点为0)。一个点的深度定义为这个节点到根的距离+1。 设dep[i]表示点i的深度,LCA(i,j)表示i与j的最近公共祖先。 有q次询问,每次询问给出l r z,求$$\sum_{l \leq i \leq r}dep[LCA(i,z)]$$
输入输出格式
输入格式:第一行2个整数n q。 接下来n-1行,分别表示点1到点n-1的父节点编号。 接下来q行,每行3个整数l r z。
输出q行,每行表示一个询问的答案。每个答案对201314取模输出
输入输出样例
5 2 0 0 1 1 1 4 3 1 4 2
8 5
说明
共5组数据,n与q的规模分别为10000,20000,30000,40000,50000。
树链剖分+线段树+差分
deep[i]是什么?——就是从 i 点到根有多少个点(包括 i )。
我们从整体上考虑,发现对于一个询问:l , r , z 来说,所有的 lca 都在 z 到根的路径上。从而有一些点,它们对很多的 lca 的深度都有贡献,而这个贡献等于在这个点下面的 lca 的个数,所以我们可以把每个 lca 到根的路径上的每个点的权值都加一。然后从 z 向上走到根,沿路统计的权值就是答案了。
就是:对于一个询问: l , r , z ,我们把每个点 i ( l <= i <= r ) 到根的路径上的每一个点的权值都加一,因为:所有的 lca 都在 z 到根的路径上,所以我们可以从 z 点向上爬到根,沿途统计的点权值之和,就是答案了。
我们每次的操作都是从某个点到根的,所以树链剖分+线段树就好了。我们每次清空线段树,然后从 l ~ r 再添加一遍,树剖+线段树的复杂度就是 n*(logn)^2 的,还要做 q 次,复杂度依然不理想。
于是想到:差分可以将询问拆开,而且每个拆开的区间之间是有重叠的,是可以转移的,而不用每次都清空。
而且差分后的数组只与右端点有关!
所以我们可以将差分后的区间按照右端点从小到大排序(左端点都是根),然后按从小到大的顺序添加点,每遇到一个询问就查询一次。
于是一波sao操作就A了。。。
附代码:
#include<iostream>
#include<algorithm>
#include<cstdio>
#define LSON rt<<1
#define RSON rt<<1|1
#define DATA(x) b[x].data
#define SIGN(x) b[x].c
#define LSIDE(x) b[x].l
#define RSIDE(x) b[x].r
#define WIDTH(x) (RSIDE(x)-LSIDE(x)+1)
#define MAXN 50010
#define MOD 201314
using namespace std;
int n,m,c=1,d=1,e=1;
int head[MAXN],deep[MAXN],fa[MAXN],son[MAXN],size[MAXN],id[MAXN],top[MAXN];
struct node1{
int next,to;
}a[MAXN];
struct node2{
int data,c,l,r;
}b[MAXN<<2];
struct node3{
int x,u,id;
bool flag;
}que[MAXN<<1];
struct node4{
int l,r;
}ans[MAXN];
inline int read(){
int date=0,w=1;char c=0;
while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
return date*w;
}
bool cmp(const node3 &x,const node3 &y){
if(x.x==y.x)return x.id<y.id;
return x.x<y.x;
}
inline void add(int x,int y){
a[c].to=y;
a[c].next=head[x];
head[x]=c++;
}
inline void addque(int l,int r,int u,int i){
que[e].x=l;que[e].u=u;que[e].id=i;
que[e++].flag=false;
que[e].x=r;que[e].u=u;que[e].id=i;
que[e++].flag=true;
}
void dfs1(int rt){
son[rt]=0;size[rt]=1;
for(int i=head[rt];i;i=a[i].next){
int will=a[i].to;
if(!deep[will]){
deep[will]=deep[rt]+1;
fa[will]=rt;
dfs1(will);
size[rt]+=size[will];
if(size[son[rt]]<size[will])son[rt]=will;
}
}
}
void dfs2(int rt,int f){
id[rt]=d++;top[rt]=f;
if(son[rt])dfs2(son[rt],f);
for(int i=head[rt];i;i=a[i].next){
int will=a[i].to;
if(will!=fa[rt]&&will!=son[rt])
dfs2(will,will);
}
}
inline void pushup(int rt){
DATA(rt)=(DATA(LSON)+DATA(RSON))%MOD;
}
inline void pushdown(int rt){
if(!SIGN(rt)||LSIDE(rt)==RSIDE(rt))return;
SIGN(LSON)=(SIGN(LSON)+SIGN(rt))%MOD;
DATA(LSON)=(DATA(LSON)+SIGN(rt)*WIDTH(LSON))%MOD;
SIGN(RSON)=(SIGN(RSON)+SIGN(rt))%MOD;
DATA(RSON)=(DATA(RSON)+SIGN(rt)*WIDTH(RSON))%MOD;
SIGN(rt)=0;
}
void buildtree(int l,int r,int rt){
int mid;
LSIDE(rt)=l;
RSIDE(rt)=r;
if(l==r){
DATA(rt)=0;
return;
}
mid=l+r>>1;
buildtree(l,mid,LSON);
buildtree(mid+1,r,RSON);
pushup(rt);
}
void update(int l,int r,int c,int rt){
int mid;
if(l<=LSIDE(rt)&&RSIDE(rt)<=r){
SIGN(rt)=(SIGN(rt)+c)%MOD;
DATA(rt)=(DATA(rt)+c*WIDTH(rt))%MOD;
return;
}
pushdown(rt);
mid=LSIDE(rt)+RSIDE(rt)>>1;
if(l<=mid)update(l,r,c,LSON);
if(mid<r)update(l,r,c,RSON);
pushup(rt);
}
int query(int l,int r,int rt){
int mid,ans=0;
if(l<=LSIDE(rt)&&RSIDE(rt)<=r)return DATA(rt);
pushdown(rt);
mid=LSIDE(rt)+RSIDE(rt)>>1;
if(l<=mid)ans=(ans+query(l,r,LSON)%MOD)%MOD;
if(mid<r)ans=(ans+query(l,r,RSON)%MOD)%MOD;
return ans%MOD;
}
void work_update(int x,int y,int k){
while(top[x]!=top[y]){
if(deep[top[x]]<deep[top[y]])swap(x,y);
update(id[top[x]],id[x],1,1);
x=fa[top[x]];
}
if(deep[x]>deep[y])swap(x,y);
update(id[x],id[y],1,1);
return;
}
int work_query(int x,int y){
int s=0;
while(top[x]!=top[y]){
if(deep[top[x]]<deep[top[y]])swap(x,y);
s=(s+query(id[top[x]],id[x],1)%MOD)%MOD;
x=fa[top[x]];
}
if(deep[x]>deep[y])swap(x,y);
s=(s+query(id[x],id[y],1)%MOD)%MOD;
return s;
}
void work(){
int now=1,id;
for(int i=1;i<e;i++){
while(now<=que[i].x){
work_update(1,now,1);
now++;
}
id=que[i].id;
if(que[i].flag)ans[id].r=work_query(1,que[i].u);
else ans[id].l=work_query(1,que[i].u);
}
for(int i=1;i<=m;i++)printf("%d\n",(ans[i].r-ans[i].l+MOD)%MOD);
}
void init(){
int x,l,r,u;
n=read();m=read();
for(int i=2;i<=n;i++){
x=read()+1;
add(x,i);
}
deep[1]=1;
dfs1(1);
dfs2(1,1);
buildtree(1,n,1);
for(int i=1;i<=m;i++){
l=read();r=read()+1;u=read()+1;
addque(l,r,u,i);
}
sort(que+1,que+e,cmp);
}
int main(){
init();
work();
return 0;
}