BZOJ3626[LNOI2014]LCA 离线+树链剖分+线段树
Posted CQzhangyu
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ3626[LNOI2014]LCA 离线+树链剖分+线段树相关的知识,希望对你有一定的参考价值。
【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; }
以上是关于BZOJ3626[LNOI2014]LCA 离线+树链剖分+线段树的主要内容,如果未能解决你的问题,请参考以下文章
BZOJ3626[LNOI2014]LCA 离线+树链剖分+线段树
BZOJ 3626: [LNOI2014]LCA 树链剖分 线段树 离线