【BZOJ 3626】 [LNOI2014]LCA【在线+主席树+树剖】

题目链接:

  TP

题解:

    可能是我比较纱布,看不懂题解,只好自己想了……

  我们考虑对于询问区间是可以差分的,然而这并没有什么卵用,然后考虑怎么统计答案。

  首先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 }
时间: 2024-10-03 06:35:47

【BZOJ 3626】 [LNOI2014]LCA【在线+主席树+树剖】的相关文章

bzoj 3626 [LNOI2014]LCA(离线处理+树链剖分,线段树)

3626: [LNOI2014]LCA Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1272  Solved: 451[Submit][Status][Discuss] Description 给出一个n个节点的有根树(编号为0到n-1,根节点为0).一个点的深度定义为这个节点到根的距离+1. 设dep[i]表示点i的深度,LCA(i,j)表示i与j的最近公共祖先. 有q次询问,每次询问给出l r z,求sigma_{l<=i<=r}dep[

BZOJ 3626: [LNOI2014]LCA [树链剖分 离线|主席树]

3626: [LNOI2014]LCA Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 2050  Solved: 817[Submit][Status][Discuss] Description 给出一个n个节点的有根树(编号为0到n-1,根节点为0).一个点的深度定义为这个节点到根的距离+1.设dep[i]表示点i的深度,LCA(i,j)表示i与j的最近公共祖先.有q次询问,每次询问给出l r z,求sigma_{l<=i<=r}dep[LC

bzoj 3626: [LNOI2014]LCA 离线+树链剖分

3626: [LNOI2014]LCA Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 426  Solved: 124[Submit][Status] 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)].(即

[BZOJ 3626] [LNOI2014] LCA 【树链剖分 + 离线 + 差分询问】

题目链接: BZOJ - 3626 题目分析 考虑这样的等价问题,如果我们把一个点 x 到 Root 的路径上每个点的权值赋为 1 ,其余点的权值为 0,那么从 LCA(x, y) 的 Depth 就是从 y 到 Root 的路径上的点权和. 这个方法是可以叠加的,这是非常有用的一点.如果我们把 [l, r] 的每个点到 Root 的路径上所有点的权值 +1,再求出从 c 到 Root 的路径点权和,即为 [l, r] 中所有点与 c 的 LCA 的 Depth 和. 不仅满足可加性,还满足可减

BZOJ 3626: [LNOI2014]LCA 树链剖分 线段树 离线

http://www.lydsy.com/JudgeOnline/problem.php?id=3626 LNOI的树链剖分题没有HAOI那么水,学到的东西还是很多的. 我如果现场写,很难想出来这种题,是时候复习一波离线算法泡脑子了.(没有暴力分的题,想不出来正解就爆零,太可怕了) 排序后离线操作通过前缀和计算答案,题解是hzwer的博客上复制的 http://hzwer.com/3891.html 直接引用清华爷gconeice的题解吧 显然,暴力求解的复杂度是无法承受的. 考虑这样的一种暴力

BZOJ 3626 [LNOI2014]LCA

一道比较神奇的题. 树链剖分+奇技淫巧: 神奇地发现,把z到跟的路径上的点值+1,查询一个点到跟的路径和就是它与z的lca的深度. 相对的,把l~r到跟的路径上的点值+1,查询z到跟的路径和就是要的答案. 考虑差分,把一个询问拆成两个,把所有询问排序然后从0~n-1到跟路径上的值+1: 一开始狂WA,发现把线段树区间加的(l-r)*v打成了(qr-ql)*v了... //Twenty #include<cstdio> #include<cstdlib> #include<io

【刷题】BZOJ 3626 [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. O

【BZOJ 3626】 [LNOI2014]LCA

3626: [LNOI2014]LCA Time Limit: 10 Sec Memory Limit: 128 MB Submit: 735 Solved: 250 [Submit][Status][Discuss] Description 给出一个n个节点的有根树(编号为0到n-1,根节点为0).一个点的深度定义为这个节点到根的距离+1. 设dep[i]表示点i的深度,LCA(i,j)表示i与j的最近公共祖先. 有q次询问,每次询问给出l r z,求sigma_{l<=i<=r}dep[L

hdu 4605 Magic Ball Game (在线主席树/离线树状数组)

hdu 4605 题意: 有一颗树,根节点为1,每一个节点要么有两个子节点,要么没有,每个节点都有一个权值wi .然后,有一个球,附带值x . 球到达某个节点上,如果x==wi,那么球停在这个节点上 .当然,这个点是叶子节点也会停止 . 如果x<wi,那么有1/2的概率走向左子树,有1/2的概率走向右子树 . 如果x>wi,那么有1/8的概率走向左子树,有7/8的概率走向右子树 . 问球经过v节点的概率 .(停在v节点也算) 解法: 在线的话每一个节点建一棵根节点到该节点的线段树,离线的话就先