zoukankan      html  css  js  c++  java
  • 树链剖分

      首先了解一下基本概念:

      重儿子:siz[u]为v的子节点中siz值最大的,那么u就是v的重儿子。
          轻儿子:v的其它子节点。
          重边:点v与其重儿子的连边。
          轻边:点v与其轻儿子的连边。
          重链:由重边连成的路径。
          轻链:轻边。

          剖分后的树有如下性质:
          性质1:如果(v,u)为轻边,则siz[u] * 2 < siz[v];
          性质2:从根到某一点的路径上轻链、重链的个数都不大于logN。

      树链剖分,如其字面意思,就是将一棵树按照轻重边剖分为多条链,使得每个节点都属于一条重链,然后按照某种顺序将链依次连接成一维结构,再通过线段树、树状数组、Splay等维护这条长链上的每一条链。

      由于重链的个数是O(logN)的,而每条链上的操作也是O(logN)的,故一次树上路径的操作的花费为O(log²N)。

      模板:

      模板题--hdu3966

      题目输入输出要求:N个点,M(M=N-1)条边,K个操作

               N个点的值

               M行 (u, v)边

               K个操作,I (或D)a b c:a~b路径上的点值加(或减)c,Q a:a节点的值

      1 #include<iostream>
      2 #include<cstring>
      3 #include<cstdio>
      4 #include<algorithm>
      5 #include<set>
      6 #include<queue>
      7 #include<vector>
      8 #pragma comment(linker, "/STACK:102400000,102400000")
      9 using namespace std;
     10 
     11 const int N = 50010, M = N * 2;
     12 const int inf = 0x3f3f3f3f;
     13 /*=============================================================*/
     14 /** 建树 */
     15 struct EG {
     16     int u, v;
     17     EG(){}
     18     EG(int u, int v) : u(u), v(v) {}
     19 } eg[M];
     20 int first[N], Next[M];
     21 int tot;
     22 void init()
     23 {
     24     tot = 0;
     25     memset(first, -1, sizeof(first));
     26 }
     27 void add_edge(int u, int v)
     28 {
     29     eg[++tot] = EG(u, v);
     30     Next[tot] = first[u], first[u] = tot;
     31     eg[++tot] = EG(v, u);
     32     Next[tot] = first[v], first[v] = tot;
     33 }
     34 
     35 /*=============================================================*/
     36 
     37 int fa[N], son[N], dep[N], dfn[N], top[N], sz[N], Rank[N], d[N];
     38 int tim;
     39 /** 以DFS序遍历整棵树并获得如下信息:
     40     sz[u] : 以u为根节点的子树的结点个数,是判断重儿子的依据
     41     son[u]: 重儿子
     42     dep[u]: u节点的深度
     43     fa[u]: u节点的父节点
     44 */
     45 void DFS1(int u)
     46 {
     47     sz[u] = 1;
     48     son[u] = -1;
     49     for(int i=first[u]; i!=-1; i=Next[i])
     50     {
     51         EG &e = eg[i];
     52         if(e.v == fa[u]) continue;
     53         dep[e.v] = dep[u] + 1;
     54         fa[e.v] = u;
     55         DFS1(e.v);
     56         sz[u] += sz[e.v];
     57         if(son[u]==-1 || sz[son[u]] < sz[e.v])
     58             son[u] = e.v;
     59     }
     60 }
     61 
     62 /**
     63     将上面产生的重链串起来,生成Rank[]和dfn[]数组。
     64     top[u]: u节点所在链的顶端节点
     65     dfn[u]: u节点的DFS时间戳,各个重链是按照时间戳的先后形成的,也就是说,线段树、树状数组维护的数列是由时间戳从小到大一次形成的
     66     Rank[t]: 时间戳为t的节点
     67 */
     68 void DFS2(int u, int tp)
     69 {
     70     top[u] = tp;
     71     dfn[u] = ++tim;
     72     Rank[tim] = u;
     73     if(son[u] == -1) return;
     74     DFS2(son[u], tp);
     75     for(int i=first[u]; i!=-1; i=Next[i])
     76     {
     77         EG &e = eg[i];
     78         if(e.v != fa[u] && e.v != son[u])
     79             DFS2(e.v, e.v);
     80     }
     81 }
     82 
     83 /** 线段树改段求点模板 */
     84 int mak[N<<2];
     85 void build(int l, int r, int rt)
     86 {
     87     mak[rt] = 0;
     88     if(l == r) {
     89         mak[rt] += d[Rank[l]];
     90         return;
     91     }
     92     int m = l + r >> 1;
     93     build(l, m, rt<<1);
     94     build(m+1, r, rt<<1|1);
     95 }
     96 
     97 void update(int L, int R, int a, int l, int r, int rt)
     98 {
     99     if(L <= l && R >= r) {
    100         mak[rt] += a;
    101         return;
    102     }
    103     int m = l + r >> 1;
    104     if(L <= m) update(L, R, a, l, m, rt<<1);
    105     if(R > m)  update(L, R, a, m+1, r, rt<<1|1);
    106 }
    107 
    108 void query(int pos, int &a, int l, int r, int rt)
    109 {
    110     a += mak[rt];
    111     if(l == r)
    112         return;
    113     int m = l + r >> 1;
    114     if(pos <= m) query(pos, a, l, m, rt<<1);
    115     else query(pos, a, m+1, r, rt<<1|1);
    116 }
    117 
    118 /*==========================================================*/
    119 
    120 /** 操作树结构上在u、v路径上的节点*/
    121 void Update(int u, int v, int a, int n)
    122 {
    123     while(top[u] != top[v]) //当u、v节点不在同一条链上
    124     {
    125         //避免分类讨论,让u代表所在链顶较低的点
    126         if(dep[top[u]] < dep[top[v]]) swap(u, v);
    127         //top[u]~u这段路径在同一条重链上,其时间戳连续,更新之
    128         update(dfn[top[u]], dfn[u], a, 1, n, 1);
    129         
    130         //向上挑至链顶的父节点
    131         /*为什么是向上跳呢?
    132             因为v点所在链的顶端高于(或就是)u点所在链的顶端,无论哪种情况,v点所在链的顶端点的父节点在u~v链上*/
    133         u = fa[top[u]];
    134     }
    135     //此时,u、v在同一条链上,甚至u=v
    136     //重链上的节点,随着向子孙延伸,时间戳是递增的,即数列序是递增的
    137     if(dep[u] > dep[v]) swap(u, v);
    138     update(dfn[u], dfn[v], a, 1, n, 1);
    139 }
    140 
    141 /*==========================================================*/
    142 
    143 int main()
    144 {
    145     int n, m, k;
    146     while(scanf("%d %d %d", &n, &m, &k) == 3)
    147     {
    148         for(int i=1; i<=n; i++) scanf("%d", d+i);
    149         int a, b, c;
    150         init();
    151         for(int i=1; i<=m; i++)
    152             scanf("%d %d", &a, &b), add_edge(a,b);
    153         char s[3];
    154         dep[1] = 0;
    155         fa[1] = 1;
    156         tim = 0;
    157         DFS1(1);
    158         DFS2(1, 1);
    159         build(1, n, 1);
    160         while(k--)
    161         {
    162             scanf("%s", s);
    163             if(s[0] == 'Q') {
    164                 scanf("%d", &a);
    165                 b = 0;
    166                 query(dfn[a], b, 1, n, 1);
    167                 printf("%d
    ", b);
    168             }
    169             else {
    170                 scanf("%d %d %d", &a, &b, &c);
    171                 Update(a, b, s[0]=='I' ? c : -c, n);
    172             }
    173         }
    174     }
    175     return 0;
    176 }
    View Code

     小结练习

          

  • 相关阅读:
    十八、SAP中使用IF/ELSE判断语句,以及sy-subrc的用法
    十七、SAP中使用SQL语句读取一条数据
    十六、SAP中查看数据库
    十五、SAP自定义结构体
    十四、SAP中定义自定义变量
    十三、SAP中定义变量时赋初始值
    十二、Sap的压缩类型p的使用方法
    十一、SAP文本变量,并设置长度
    十、SAP小数需要用引号括起来
    九、SAP中使用定义时间及使用sy-uzeit取当前时间
  • 原文地址:https://www.cnblogs.com/WCB-ACM/p/5245818.html
Copyright © 2011-2022 走看看