Description
给出一个$n$个节点的有根树(编号为$0$到$n-1$,根节点为$0$)。
一个点的深度定义为这个节点到根的距离$+1$。
设$dep[i]$表示点$i$的深度,$lca(i,j)$表示$i,j$的最近公共祖先。
有$q$次询问,每次询问给出$l;r;z$,求$sum_{i=l}^{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
Sample Output
8
5
HINT
$n,q;leq;50000$。
Solution
对于两个点$x,y$,求$dep[lca(x,y)]$,可以将$x$到根上的点全部打标记,求$y$向上第一个有标记的点的深度.
即,将$x$到根的路径上的点点权设为$1$,求$y$到根的路径权值和.
从$0$到$1$依次插入点$x$,将$x$到根的路径上的点点权$+1$.
离线处理类似前缀和的方式处理每个询问.
#include<cmath> #include<ctime> #include<queue> #include<stack> #include<cstdio> #include<vector> #include<cstring> #include<cstdlib> #include<iostream> #include<algorithm> #define N 50005 #define M 201314 #define K 150005 using namespace std; struct graph{ int nxt,to; }e[N]; struct quest{ int x,z,n,ans; }l[N],r[N]; struct linetree{ int l,r,s,len,lzy; }lt[K]; int g[N],n,q,t1,t2,cnt; int f[N],p[N],dep[N],top[N],siz[N],son[N]; inline int read(){ int ret=0;char c=getchar(); while(!isdigit(c)) c=getchar(); while(isdigit(c)){ ret=(ret<<1)+(ret<<3)+c-'0'; c=getchar(); } return ret; } inline void addedge(int x,int y){ e[++cnt].nxt=g[x];g[x]=cnt;e[cnt].to=y; } inline void dfs1(int u){ int m=0;siz[u]=1; for(int i=g[u];i;i=e[i].nxt){ f[e[i].to]=u; dep[e[i].to]=dep[u]+1; dfs1(e[i].to); siz[u]+=siz[e[i].to]; if(siz[e[i].to]>m){ son[u]=e[i].to; m=siz[e[i].to]; } } } inline void dfs2(int u,int tp){ top[u]=tp;p[u]=++cnt; if(son[u]) dfs2(son[u],tp); for(int i=g[u];i;i=e[i].nxt) if(e[i].to!=son[u]) dfs2(e[i].to,e[i].to); } inline void build(int u,int l,int r){ lt[u].l=l;lt[u].r=r;lt[u].len=lt[u].r-lt[u].l+1; if(lt[u].l<lt[u].r){ int lef=u<<1,rig=u<<1|1; int mid=lt[u].l+lt[u].r>>1; build(lef,l,mid);build(rig,mid+1,r); } } inline int cover(int u,int l,int r){ if(lt[u].l>=l&<[u].r<=r){ ++lt[u].lzy; lt[u].s=(lt[u].s+lt[u].len)%M; } else if(lt[u].l<lt[u].r){ int lef=u<<1,rig=u<<1|1; int mid=lt[u].l+lt[u].r>>1; if(lt[u].lzy){ lt[lef].lzy+=lt[u].lzy; lt[rig].lzy+=lt[u].lzy; lt[lef].s=(lt[lef].s+lt[lef].len*lt[u].lzy)%M; lt[rig].s=(lt[rig].s+lt[rig].len*lt[u].lzy)%M; lt[u].lzy=0; } if(l<=mid) cover(lef,l,r); if(r>mid) cover(rig,l,r); lt[u].s=(lt[lef].s+lt[rig].s)%M; } } inline int ask(int u,int l,int r){ if(lt[u].l>=l&<[u].r<=r) return lt[u].s; if(lt[u].l<lt[u].r){ int lef=u<<1,rig=u<<1|1,ret=0; int mid=lt[u].l+lt[u].r>>1; if(lt[u].lzy){ lt[lef].lzy+=lt[u].lzy; lt[rig].lzy+=lt[u].lzy; lt[lef].s=(lt[lef].s+lt[lef].len*lt[u].lzy)%M; lt[rig].s=(lt[rig].s+lt[rig].len*lt[u].lzy)%M; lt[u].lzy=0; } if(l<=mid) ret=(ret+ask(lef,l,r))%M; if(r>mid) ret=(ret+ask(rig,l,r))%M; return ret; } } inline void add(int x,int y){ int t; while(top[x]!=top[y]){ if(dep[top[x]]<dep[top[y]]){ t=x;x=y;y=t; } cover(1,p[top[x]],p[x]); x=f[top[x]]; } if(p[x]>p[y]){ t=x;x=y;y=t; } cover(1,p[x],p[y]); } inline int que(int x,int y){ int ret=0,t; while(top[x]!=top[y]){ if(dep[top[x]]<dep[top[y]]){ t=x;x=y;y=t; } ret=(ret+ask(1,p[top[x]],p[x]))%M; x=f[top[x]]; } if(p[x]>p[y]){ t=x;x=y;y=t; } ret=(ret+ask(1,p[x],p[y]))%M; return ret; } inline bool cmp1(quest x,quest y){ return x.x<y.x; } inline bool cmp2(quest x,quest y){ return x.n<y.n; } inline void Aireen(){ n=read();q=read(); for(int i=2,j;i<=n;++i){ j=read()+1;addedge(j,i); } for(int i=1;i<=q;++i){ l[i].n=r[i].n=i; l[i].x=read(); r[i].x=read()+1; l[i].z=r[i].z=read()+1; } sort(l+1,l+1+q,cmp1); sort(r+1,r+1+q,cmp1); while(t1<=q&&!l[t1].x) ++t1; while(t2<=q&&!r[t2].x) ++t2; dep[1]=1;dfs1(1); cnt=0;dfs2(1,1); build(1,1,n); for(int i=1;i<=n;++i){ add(1,i); while(t1<=q&&l[t1].x==i){ l[t1].ans=que(1,l[t1].z);++t1; } while(t2<=q&&r[t2].x==i){ r[t2].ans=que(1,r[t2].z);++t2; } } sort(l+1,l+1+q,cmp2); sort(r+1,r+1+q,cmp2); for(int i=1;i<=q;++i) printf("%d ",(r[i].ans-l[i].ans+M)%M); } int main(){ freopen("lca.in","r",stdin); freopen("lca.out","w",stdout); Aireen(); fclose(stdin); fclose(stdout); return 0; }