• 初识树链剖分


    参考博客:https://www.cnblogs.com/George1994/p/7821357.html

      模板题:HDU 3966 Aragorn's Story

      给一棵树每个点有权值,三种操作,一是给两个点和一个值U, V,K,U~V这条路径上所有点+K,二是U~K这条路径上所有点权值-K,三是查询某点U的权值为多少。先写着树链剖分  

      1 #include <iostream>
      2 #include <string.h>
      3 #include <cstdio>
      4 #include <vector>
      5 #include <queue>
      6 #include <math.h>
      7 #include <string>
      8 #include <algorithm>
      9 #include <time.h>
     10 
     11 #define SIGMA_SIZE 26
     12 #define lson rt<<1
     13 #define rson rt<<1|1
     14 #define lowbit(x) (x&-x)
     15 #define foe(i, a, b) for(int i=a; i<=b; i++)
     16 #define fo(i, a, b) for(int i = a; i < b; i++);
     17 #pragma warning ( disable : 4996 )
     18 #pragma comment(linker, "/STACK:1024000000,1024000000")
     19 
     20 using namespace std;
     21 typedef long long LL;
     22 inline LL LMax(LL a,LL b)      { return a>b?a:b; }
     23 inline LL LMin(LL a,LL b)      { return a>b?b:a; }
     24 inline LL lgcd( LL a, LL b )   { return b==0?a:lgcd(b,a%b); }
     25 inline LL llcm( LL a, LL b )   { return a/lgcd(a,b)*b; }  //a*b = gcd*lcm
     26 inline int Max(int a,int b)    { return a>b?a:b; }
     27 inline int Min(int a,int b)       { return a>b?b:a; }
     28 inline int gcd( int a, int b ) { return b==0?a:gcd(b,a%b); }
     29 inline int lcm( int a, int b ) { return a/gcd(a,b)*b; }  //a*b = gcd*lcm
     30 const LL INF = 0x3f3f3f3f3f3f3f3f;
     31 const LL mod  = 1000000007;
     32 const double eps = 1e-8;
     33 const int inf  = 0x3f3f3f3f;
     34 const int maxk = 1e6+5;
     35 const int maxn = 5e4+5;
     36 
     37 int N, M, Q, tim;
     38 int cnt;
     39 int linjie[maxn];
     40 int sum[maxn<<2], lazy[maxn<<2];
     41 int siz[maxn]; //以i为根节点 它的子树的节点个数
     42 int top[maxn]; //当前节点所在链的顶端节点编号
     43 int son[maxn]; //重儿子编号
     44 int faz[maxn]; //当前节点的父亲节点
     45 int dep[maxn]; //深度,
     46 int tid[maxn]; //树中每个节点剖分以后的新编号(dfs执行顺序)
     47 int rnk[maxn]; //当前节点在树中的位置
     48 struct node {
     49     int to, next, val; 
     50 }pp[2*maxn];
     51 
     52 void addedge(int u, int v)
     53 { pp[cnt].to = v; pp[cnt].next = linjie[u]; linjie[u] = cnt++; }
     54 
     55 //第一次dfs更新了dep,faz,siz,son数组
     56 void dfs_1(int u, int fa, int d)
     57 {
     58     dep[u] = d;
     59     faz[u] = fa;
     60     siz[u] = 1;
     61     for ( int i = linjie[u]; ~i; i = pp[i].next)
     62     {
     63         int v = pp[i].to;
     64         if ( v != faz[u] )
     65         {
     66             dfs_1(v, u, d+1);
     67             // 收敛的时候将当前结点的siz加上子结点的siz
     68             siz[u] += siz[v];
     69             // 如果没有设置过重结点son或者子结点v的siz大于之前记录的重结点son,则进行更新
     70             if (son[u] == -1 || siz[v] > siz[son[u]])
     71                 son[u] = v;
     72         }
     73     }
     74 }
     75 
     76 void dfs_2(int u, int tp)
     77 {
     78     top[u] = tp;        // 设置当前结点的起点为tP
     79     tid[u] = ++tim;        // 设置当前结点的dfs执行序号
     80     rnk[tid[u]] = u;    // 设置dfs序号对应成当前结点
     81 
     82     // 如果当前结点没有处在重链上,则不处理
     83     if (son[u] == -1) return;
     84     // 将这条重链上的所有的结点都设置成起始的重结点
     85     dfs_2(son[u], tp);
     86 
     87     for ( int i = linjie[u]; ~i; i = pp[i].next )
     88     {
     89         // 如果连接结点不是当前结点的重子结点并且也不是u的父亲结点,
     90         // 则将其的top设置成自己,进一步递归
     91         int v = pp[i].to;
     92         if (v != son[u] && v != faz[u])
     93             dfs_2(v, v);
     94     }
     95 }
     96 
     97 void pushUp(int rt)
     98 { sum[rt] = Max(sum[lson], sum[rson]); }
     99 
    100 void pushDown(int rt, int ln, int rn)
    101 {
    102     if (lazy[rt])
    103     {
    104         lazy[lson] += lazy[rt];
    105         lazy[rson] += lazy[rt];
    106 
    107         sum[lson] += ln*lazy[rt];
    108         sum[rson] += rn*lazy[rt];
    109 
    110         lazy[rt] = 0;
    111     }
    112 }
    113 
    114 void build(int rt, int L, int R)
    115 {
    116     lazy[rt] = 0;
    117     if ( L == R )
    118     {
    119         //L是dfs遍历顺序编号,rnk[L]是原来的点的编号
    120         sum[rt] = pp[rnk[L]].val;
    121         return;
    122     }
    123 
    124     int mid = (L+R)>>1;
    125     build(lson, L, mid);
    126     build(rson, mid+1, R);
    127     pushUp(rt);
    128 }
    129 
    130 void update(int rt, int L, int R, int lhs, int rhs, int C)
    131 {
    132     if ( lhs <= L && rhs >= R )
    133     {
    134         lazy[rt] += C;
    135         sum[rt] += C*(R-L+1);
    136         return;
    137     }
    138 
    139     int mid = (L+R)>>1;
    140     pushDown(rt, mid-L+1, R-mid);
    141     if ( lhs <= mid ) update(lson, L, mid, lhs, rhs, C);
    142     if ( rhs >  mid ) update(rson, mid+1, R, lhs, rhs, C);
    143     pushUp(rt);
    144 }
    145 
    146 int query(int rt, int L, int R, int V)
    147 {
    148     if ( L == R )
    149         return sum[rt];
    150 
    151     int tmp = -1, mid = (L+R)>>1;
    152     pushDown(rt, mid-L+1, R-mid);
    153     if ( V <= mid ) tmp = query(lson, L, mid, V);
    154     else tmp = query(rson, mid+1, R, V);
    155 
    156     pushUp(rt);
    157     return tmp;
    158 }
    159 
    160 void change(int x, int y, int val)
    161 {
    162     while (top[x] != top[y])
    163     {
    164         //x作为找深度深的那一个节点
    165         if (dep[top[x]] < dep[top[y]]) swap(x, y);
    166         //将x作为一个区间的结尾,top[x]作为一个区间的起始
    167         update(1, 1, N, tid[top[x]], tid[x], val);
    168         //跳到更上层的链
    169         x = faz[top[x]];        
    170     }
    171 
    172     //直到x和y是在同一条链上
    173     if (dep[x] > dep[y]) swap(x, y);
    174     update(1, 1, N, tid[x], tid[y], val);
    175 }
    176 
    177 void init()
    178 {
    179     tim = cnt = 0;
    180     memset(linjie, -1, sizeof(linjie));
    181     memset(son, -1, sizeof(son));
    182 
    183     int x, y;
    184     foe(i, 1, N)
    185         scanf("%d", &pp[i].val);
    186     foe(i, 1, M)
    187     {
    188         scanf("%d %d", &x, &y);
    189         addedge(x, y);
    190         addedge(y, x);
    191     }
    192 
    193     //父节点是0, 深度为0
    194     dfs_1(1, 0, 0);
    195     dfs_2(1, 1);
    196     build(1, 1, N);
    197 }
    198 
    199 
    200 int main()
    201 {
    202     while ( ~scanf("%d %d %d", &N, &M, &Q) )
    203     {
    204         init();
    205 
    206         char str[2];
    207         int x, y, d;
    208         while (Q--)
    209         {
    210             scanf("%s", str);
    211             if (str[0] == 'I') {
    212                 scanf("%d %d %d", &x, &y, &d);
    213                 change(x, y, d);
    214             }
    215             else if (str[0] == 'D') {
    216                 scanf("%d %d %d", &x, &y, &d);
    217                 change(x, y, -d);
    218             }
    219             else {
    220                 scanf("%d", &d);
    221                 printf("%d
    ", query(1, 1, N, tid[d]));
    222             }
    223         }
    224     }
    225     return 0;
    226 }
    View Code
  • 相关阅读:
    parent和top
    history
    [矩阵快速幂]T-shirt(2018江苏邀请赛I题)
    [学习]Java学习
    [数论]Factors of Factorial
    [RMQ][ST算法]Frequent values
    [二维树状数组]计数问题
    [树状数组]Mishka and Interesting sum(codeforces703D)
    [简单思维题]Snuke's Coloring 2-1
    [树状数组][逆序数]Ultra-QuickSort
  • 原文地址:https://www.cnblogs.com/chaoswr/p/9362312.html
Copyright © 2020-2023  润新知