BZOJ 3626 [LNOI2014]LCA在线+主席树+树剖
Posted Troy Ricardo
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ 3626 [LNOI2014]LCA在线+主席树+树剖相关的知识,希望对你有一定的参考价值。
题目链接:
题解:
可能是我比较纱布,看不懂题解,只好自己想了……
我们考虑对于询问区间是可以差分的,然而这并没有什么卵用,然后考虑怎么统计答案。
首先LCA一定是z的祖先(这里说的祖先包括自己,以下祖先均为此概念)节点,也就是是说我们只要计算出每个祖先节点的贡献就可以了,再考虑每个祖先的贡献如何计算。
我们发现对于深度其实是该点到root的路径点数,所以我们可以这样想,我们询问z的祖先的答案,就是在计算有对于给定区间有多少个点经过了z的祖先。
那么思路到这里就很清晰了,我们先把每个点到root的路径上的点权都加1,在询问的时候用历史版本做差分即可,那么带永久化标记的主席树+树剖啊QwQ。
至于时间复杂度,有理有据的$O(nlog^2)$。
代码:
1 #define Troy 2 3 #include <bits/stdc++.h> 4 5 using namespace std; 6 7 inline int read(){ 8 int s=0,k=1;char ch=getchar(); 9 while(ch<‘0‘|ch>‘9‘) ch==‘-‘?k=-1:0,ch=getchar(); 10 while(ch>47&ch<=‘9‘) s=s*10+(ch^48),ch=getchar(); 11 return s*k; 12 } 13 14 const int N=5e4+5,mod=201314; 15 16 int n,Q; 17 18 struct edges{ 19 int v;edges *last; 20 }edge[N<<1],*head[N];int cnt; 21 22 inline void push(int u,int v){ 23 edge[++cnt]=(edges){v,head[u]};head[u]=edge+cnt; 24 } 25 26 class Persistent_Segment_tree{ 27 public: 28 inline void add(int pos,int l,int r){ 29 add(root[pos-1],root[pos],1,n,l,r); 30 } 31 inline int query(int last,int pos,int l,int r){ 32 return query(root[last-1],root[pos],1,n,l,r,0); 33 } 34 inline void build(){ 35 root[0]=tree; 36 root[0]->lc=tree; 37 root[0]->rc=tree; 38 cnt_tree=1; 39 } 40 inline int out(){ 41 return cnt_tree; 42 } 43 private: 44 struct Tree{ 45 Tree *lc,*rc; 46 int sign_per,val; 47 Tree(){sign_per=val=0;lc=rc=NULL;} 48 }tree[N<<7],*root[N<<5];int cnt_tree; 49 inline void add(Tree *p,Tree *&u,int l,int r,int x,int y){ 50 u=tree+cnt_tree;cnt_tree++; 51 *u=*p; 52 u->val+=y-x+1; 53 u->val%=mod; 54 if(x<=l&&r<=y){;u->sign_per++;return;} 55 int mid=l+r>>1; 56 if(x>mid) add(p->rc,u->rc,mid+1,r,x,y); 57 else if(y<=mid) add(p->lc,u->lc,l,mid,x,y); 58 else add(p->lc,u->lc,l,mid,x,mid),add(p->rc,u->rc,mid+1,r,mid+1,y); 59 } 60 inline int query(Tree *p,Tree *u,int l,int r,int x,int y,int sign_p){ 61 if(x<=l&&r<=y){ 62 return (sign_p*1ll*(r-l+1)%mod+u->val-p->val)%201314+mod; 63 } 64 int mid=l+r>>1,ret=0; 65 if(y>mid) ret+=query(p->rc,u->rc,mid+1,r,x,y,sign_p+u->sign_per-p->sign_per); 66 if(x<=mid) ret+=query(p->lc,u->lc,l,mid,x, y, sign_p+u->sign_per-p->sign_per); 67 return ret%201314; 68 } 69 }war; 70 71 int fa[N],g[N],size[N],heavy[N],tid[N],idx,deep[N],L[N],R[N]; 72 73 inline void dfs(int x){ 74 size[x]=1; 75 for(edges *i=head[x];i;i=i->last) if(i->v!=fa[x]){ 76 deep[i->v]=deep[x]+1,fa[i->v]=x,dfs(i->v); 77 size[x]+=size[i->v]; 78 if(size[heavy[x]]<size[i->v]) 79 heavy[x]=i->v; 80 } 81 } 82 83 inline void dfs(int x,int grand){ 84 tid[x]=++idx; 85 g[x]=grand; 86 if(heavy[x]){ 87 dfs(heavy[x],grand); 88 for(edges *i=head[x];i;i=i->last) if(i->v!=fa[x]&&i->v!=heavy[x]){ 89 dfs(i->v,i->v); 90 } 91 } 92 } 93 94 inline void add(int x){ 95 L[x]=idx+1; 96 int t=x; 97 while(g[x]!=1){ 98 ++idx; 99 war.add(idx,tid[g[x]],tid[x]); 100 x=fa[g[x]]; 101 } 102 ++idx,war.add(idx,tid[1],tid[x]); 103 R[t]=idx; 104 } 105 106 inline int query(int x,int l,int r){ 107 int ret=0; 108 while(g[x]!=1){ 109 (ret+=war.query(L[l],R[r],tid[g[x]],tid[x]))%=mod; 110 x=fa[g[x]]; 111 } 112 ret+=war.query(L[l],R[r],tid[1],tid[x]); 113 return ret%mod; 114 } 115 116 int main(){ 117 n=read(),Q=read(); 118 for(int i=2;i<=n;++i){ 119 int x=read()+1; 120 push(x,i),push(i,x); 121 } 122 dfs(1);dfs(1,1);idx=0; 123 war.build(); 124 for(int i=1;i<=n;++i){ 125 add(i); 126 } 127 while(Q--){ 128 int l=read()+1,r=read()+1,z=read()+1; 129 printf("%d\n",(query(z,l,r)%mod+mod)%mod); 130 } 131 }
以上是关于BZOJ 3626 [LNOI2014]LCA在线+主席树+树剖的主要内容,如果未能解决你的问题,请参考以下文章
BZOJ 3626: [LNOI2014]LCA [树链剖分 离线|主席树]