【数据结构】——树链剖分

树链剖分——简单而强大的数据维护方法

只是放个板子而已。

用我的码风覆盖了的。

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 //------------------------------------------------------
  4 inline int read(){
  5     int f=1,x=0;
  6     char c=getchar();
  7     while(!isdigit(c)){
  8         if(c==‘-‘) f=-1;
  9         c=getchar();
 10     }
 11     while(isdigit(c)){
 12         x=x*10+c-‘0‘;
 13         c=getchar();
 14     }
 15     return x*f;
 16 }
 17 //------------------------------------------------------
 18 const int N=2e5+10;
 19 int at[N<<1],sum[N<<1];
 20 int head[N],cnt,n,m,r,mod,tot,ans;
 21 int w[N],dep[N],siz[N],fa[N],son[N],top[N],id[N],w2[N];
 22 struct edge{ int to,next; }e[N<<1];
 23 inline void addedge(int from,int to){ e[++cnt]=(edge){to,head[from]};head[from]=cnt; }
 24 inline void add(int x,int y){addedge(x,y),addedge(y,x);}
 25 //-------------------------------------------------------
 26 void dfs1(int u,int f){
 27     dep[u]=dep[f]+1;
 28     siz[u]=1;
 29     fa[u]=f;
 30     int maxson=0;
 31     for(int i=head[u];i;i=e[i].next){
 32         int v=e[i].to;
 33         if(v==f) continue;
 34         dfs1(v,u);
 35         siz[u]+=siz[v];
 36         if(siz[v]>maxson) maxson=siz[v],son[u]=v;
 37     }
 38 }
 39 void dfs2(int u,int f){
 40     id[u]=++tot;
 41     w2[tot]=w[u];
 42     top[u]=f;
 43     if(!son[u]) return;
 44     dfs2(son[u],f);
 45     for(int i=head[u];i;i=e[i].next){
 46         int v=e[i].to;
 47         if(v==fa[u]||v==son[u]) continue;
 48         dfs2(v,v);
 49     }
 50 }
 51 //-------------------------------------------------------
 52 class Tree{
 53     private:
 54         inline int ls(int o){return o<<1;}
 55         inline int rs(int o){return o<<1|1;}
 56         inline void pushdown(int o,int l,int r){
 57             if(!at[o]) return;
 58             int mid=(l+r)>>1;
 59             sum[ls(o)]=(sum[ls(o)]+at[o]*(mid-l+1))%mod;
 60             sum[rs(o)]=(sum[rs(o)]+at[o]*(r-mid))%mod;
 61             at[ls(o)]=(at[ls(o)]+at[o])%mod;
 62             at[rs(o)]=(at[rs(o)]+at[o])%mod;
 63             at[o]=0;
 64         }
 65         inline void pushup(int o){ sum[o]=(sum[ls(o)]+sum[rs(o)])%mod;}
 66     public:
 67         void build(int o,int l,int r){
 68             if(l==r){
 69                 sum[o]=w2[l];
 70                 if(sum[o]>mod) sum[o]%=mod;
 71                 return;
 72             }
 73             int mid=(l+r)>>1;
 74             build(ls(o),l,mid);
 75             build(rs(o),mid+1,r);
 76             pushup(o);
 77         }
 78         void change(int o,int l,int r,int x,int y,int k){
 79             if(l>y||r<x) return;
 80             if(x<=l&&r<=y){
 81                 sum[o]+=(r-l+1)*k;
 82                 at[o]+=k;
 83                 return;
 84             }
 85             int mid=(l+r)>>1;
 86             pushdown(o,l,r);
 87             if(x<=mid) change(ls(o),l,mid,x,y,k);
 88             if(y>mid) change(rs(o),mid+1,r,x,y,k);
 89             pushup(o);
 90         }
 91         void query(int o,int l,int r,int x,int y){
 92             if(l>y||r<x) return;
 93             if(x<=l&&r<=y){
 94                 ans+=sum[o];
 95                 ans%=mod;
 96                 return;
 97             }
 98             int mid=(l+r)>>1;
 99             pushdown(o,l,r);
100             if(x<=mid) query(ls(o),l,mid,x,y);
101             if(y>mid) query(rs(o),mid+1,r,x,y);
102         }
103         inline int ask(int u,int v){
104             int cur=0;
105             while(top[u]!=top[v]){
106                 if(dep[top[u]]<dep[top[v]]) swap(u,v);
107                 ans=0;
108                 query(1,1,n,id[top[u]],id[u]);
109                 cur+=ans;
110                 cur%=mod;
111                 u=fa[top[u]];
112             }
113             ans=0;
114             if(dep[u]>dep[v]) swap(u,v);
115             query(1,1,n,id[u],id[v]);
116             cur+=ans;
117             return cur%mod;
118         }
119         inline void ask2(int u,int v,int k){
120             k%=mod;
121             while(top[u]!=top[v]){
122                 if(dep[top[u]]<dep[top[v]]) swap(u,v);
123                 change(1,1,n,id[top[u]],id[u],k);
124                 u=fa[top[u]];
125             }
126             if(dep[u]>dep[v]) swap(u,v);
127             change(1,1,n,id[u],id[v],k);
128         }
129 }T;
130 //-------------------------------------------------------
131 int main(){
132     n=read();m=read();r=read();mod=read();
133     int k,x,y,z;
134     for(register int i=1;i<=n;i++) w[i]=read();
135     for(register int i=1;i<n;i++) add(read(),read());
136     dfs1(r,0);
137     dfs2(r,r);
138     T.build(1,1,n);
139     for(register int i=1;i<=m;i++){
140         k=read();
141         if(k==1){
142             x=read();y=read();z=read();
143             T.ask2(x,y,z);
144         }
145         else if(k==2){
146             x=read();y=read();
147             printf("%d\n",T.ask(x,y));
148         }
149         else if(k==3){
150             x=read();z=read();
151             T.change(1,1,n,id[x],id[x]+siz[x]-1,z);
152         }
153         else{
154             x=read();ans=0;
155             T.query(1,1,n,id[x],id[x]+siz[x]-1);
156             printf("%d\n",ans);
157         }
158     }
159     return 0;
160 } 

原文地址:https://www.cnblogs.com/Nelson992770019/p/11826788.html

时间: 2024-08-11 06:23:29

【数据结构】——树链剖分的相关文章

数据结构&#183;树链剖分+LCT

于是两个一起搞了... 怎么说,写的是P党风格的C++,短也不会短到哪里去,跑起来也不快,常数大成狗OTL BZOJ 1036 树链的经典题吧,点修改+路经询问 [Code] BZOJ 2243 路径修改+路径询问 [Code] BZOJ 3083 路径修改+子树询问(根可变),这道题要用树链剖分求DFS序中某一段区间的值(DFS序可查子树,链剖可修改路径,两者相结合就行了) [Code] BZOJ 2049 用LCT维护森林形态 [Code] BZOJ 2631 路径修改+路径询问+形态可变

数据结构(树链剖分):BZOJ 4034: [HAOI2015]T2

Description 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三种: 操作 1 :把某个节点 x 的点权增加 a . 操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a . 操作 3 :询问某个节点 x 到根的路径中所有点的点权和. Input 第一行包含两个整数 N, M .表示点数和操作数. 接下来一行 N 个整数,表示树中节点的初始权值. 接下来 N-1 行每行三个正整数 fr, to , 表示该树中存在一条边 (fr, to) . 再

数据结构(树链剖分):COGS 2109. [NOIP2015] 运输计划

2109. [NOIP2015] 运输计划 ★★★   输入文件:transport.in   输出文件:transport.out   简单对比时间限制:1 s   内存限制:256 MB [题目描述] 公元 2044 年,人类进入了宇宙纪元. L 国有 n 个星球,还有 n-1 条双向航道,每条航道建立在两个星球之间,这 n-1 条航道连通了 L 国的所有星球. 小 P 掌管一家物流公司,该公司有很多个运输计划,每个运输计划形如:有一艘物 流飞船需要从 ui 号星球沿最快的宇航路径飞行到 v

数据结构(树链剖分,堆):HNOI 2016 network

2215. [HNOI2016]网络 ★★★☆   输入文件:network_tenderRun.in   输出文件:network_tenderRun.out   简单对比时间限制:2 s   内存限制:128 MB [题目描述] [输入格式] [输出格式] [样例输入1] 13 23 1 2 1 3 2 4 2 5 3 6 3 7 4 8 4 9 6 10 6 11 7 12 7 13 2 1 0 8 13 3 0 9 12 5 2 9 2 8 2 2 0 10 12 1 2 2 1 3 2

浅析树链剖分Orz

本文思路参考自何开大佬 引子 相信各位大佬一定会线段树这种非常实用的数据结构 那么如果我们要维护一棵树上的链的权值的时候怎么办 就比如说BZOJ1036树的统计这道题目 可能诸位草率地想想线段树是可以口头AC的,But 这是在一棵树上,线段树支持的连续的区间操作 在这棵树上,如果链的编号断断续续,那么我们的线段树就和暴力没有什么区别有一点点区别了 概念 所以这里就需要用到树链剖分,这种可以支持树上链操作的数据结构 树链剖分有很多高大上的名词需要我们去记 我们先定义一些概念东东 size[u]表示

【数据结构】树链剖分

百度百科 Definition 在处理树上的链上修改与询问问题时,如果朴素地采用LCA的手段,那么询问的复杂度是\(O(logn)\),但是修改的复杂度会成为朴素地\(O(n)\),这在大部分题目中是难以接受的.用于处理树上两点间简单路径上权值和与单点子树权值和的修改以及其查询问题的数据结构与处理方法,被叫做树链剖分. Solution 考虑在一位的数列上做区间查询与修改,可以使用线段树做到每次修改\(O(logn)\)的复杂度.那么考虑在树上能否使用线段树.最简单的思想是给每个节点一个DFS序

数据结构之树链剖分

首先了解一下基本概念: 重儿子:siz[u]为v的子节点中siz值最大的,那么u就是v的重儿子.      轻儿子:v的其它子节点.      重边:点v与其重儿子的连边.      轻边:点v与其轻儿子的连边.      重链:由重边连成的路径.      轻链:轻边. 剖分后的树有如下性质:      性质1:如果(v,u)为轻边,则siz[u] * 2 < siz[v]:      性质2:从根到某一点的路径上轻链.重链的个数都不大于logN. 树链剖分,如其字面意思,就是将一棵树按照轻重

数据结构(并查集||树链剖分):HEOI 2016 tree

[注意事项] 为了体现增强版,题目限制和数据范围有所增强: 时间限制:1.5s 内存限制:128MB 对于15% 的数据,1<=N,Q<=1000. 对于35% 的数据,1<=N,Q<=10000. 对于50% 的数据,1<=N,Q<=100000,且数据均为官方数据. 对于100% 的数据,1<=N,Q<=1000000. 请注意常数因子对于程序运行的影响. 并查集很简单,并查集就是倒序处理,表示删除一个点的标记,删除后不会再加回来,删完后,合并当前点与其

树链剖分简(单)介(绍)

树链剖分可以算是一种数据结构(一大堆数组,按照这个意思,主席树就是一大堆线段树).将一棵树分割成许多条连续的树链,方便完成一下问题: 单点修改(dfs序可以完成) 求LCA(各种乱搞也可以) 树链修改(修改任意树上两点之间的唯一路径) 树链查询 (各种操作)  前两个内容可以用其他方式解决,但是下面两种操作倍增.st表,dfs序就很难解决(解决当然可以解决,只是耗时长点而已).下面开始步入正题. 树链剖分的主要目的是分割树,使它成一条链,然后交给其他数据结构(如线段树,Splay)来进行维护.常