• bzoj4034: [HAOI2015]树上操作(树链剖分)


    bzoj4034

    题目描述:给定一个n个点的树,有m次操作,操作分3种。

                     1、将某个节点的点权增加x。

                     2、将以某个节点x为根的子树中所有点的权值加上a。

                     3、询问某个节点x到根节点的所有点权和。

    输入格式:第一行两个整数,表示树的节点个数n和操作个数m。

                     第二行n个整数,表示每个节点的权值。

                     接下来n - 1行每行两个整数,描述这棵树。

                     接下来m行描述了m个操作。

    输出格式:对于每个询问操作,输出每行一个整数表示点权和。

    输入样例:

    5 5
    1 2 3 4 5
    1 2
    1 4
    2 3
    2 5
    3 3
    1 2 1
    3 5
    2 1 2
    3 3

    输出样例:

    6
    9
    13

    解析:又是一道树剖的模板题,直接上树剖就好了。

    代码如下:

      1 #include<cstdio>
      2 #include<vector>
      3 #define ll long long
      4 #define lc o << 1
      5 #define rc o << 1 | 1
      6 using namespace std;
      7 
      8 const int maxn = 1e5 + 5;
      9 int n, m, val[maxn];
     10 ll sum[maxn * 4], bj[maxn * 4];
     11 int dep[maxn], fa[maxn], top[maxn], size[maxn], seq[maxn], cnt, dfn[maxn], heavy[maxn];
     12 vector <int> ve[maxn];
     13 
     14 int read(void) {
     15     char c; while (c = getchar(), (c < '0' || c > '9') && c != '-'); int x = 0, y = 1;
     16     if (c == '-') y = -1; else x = c - '0';
     17     while (c = getchar(), c >= '0' && c <= '9') x = x * 10 + c - '0'; return x * y; 
     18 }
     19 
     20 void dfs1(int u, int pre) {
     21     dep[u] = dep[pre] + 1;
     22     fa[u] = pre; size[u] = 1;
     23       for (int i = 0; i < ve[u].size(); ++ i) {
     24           int v = ve[u][i];
     25             if (v == pre) continue;
     26           dfs1(v, u);
     27           size[u] += size[v];
     28             if (size[v] > size[heavy[u]]) heavy[u] = v;
     29       }
     30 }
     31 
     32 void dfs2(int u, int cur) {
     33     top[u] = cur; dfn[u] = ++ cnt; 
     34     seq[cnt] = u;
     35       if (!heavy[u]) return;
     36     dfs2(heavy[u], cur);
     37       for (int i = 0; i < ve[u].size(); ++ i) {
     38           int v = ve[u][i];
     39             if (v == fa[u] || v == heavy[u]) continue;
     40           dfs2(v, v);
     41       }
     42 }
     43 
     44 void build(int o, int l, int r) {
     45     if (l == r) {
     46       sum[o] = val[seq[l]]; return;
     47     }
     48     int mid = l + r >> 1;
     49     build(lc, l, mid); build(rc, mid + 1, r);
     50     sum[o] = sum[lc] + sum[rc];
     51 }
     52 
     53 void pushdown(int o, int l, int r) {
     54     int mid = l + r >> 1;
     55     sum[lc] += bj[o] * (mid - l + 1);
     56     sum[rc] += bj[o] * (r - mid);
     57     bj[lc] += bj[o]; bj[rc] += bj[o]; bj[o] = 0;
     58 }
     59 
     60 void modify(int o, int l, int r, int ql, int qr, int c) {
     61     if (ql <= l && qr >= r) {
     62       sum[o] += 1ll * c * (r - l + 1); bj[o] += c;
     63       return;
     64     }
     65     int mid = l + r >> 1;
     66     if (bj[o]) pushdown(o, l, r);
     67     if (ql <= mid) modify(lc, l, mid, ql, qr, c);
     68     if (qr > mid) modify(rc, mid + 1, r, ql, qr, c);
     69     sum[o] = sum[lc] + sum[rc];
     70 }
     71 
     72 ll query(int o, int l, int r, int ql, int qr) {
     73     if (ql <= l && qr >= r) return sum[o];
     74     int mid = l + r >> 1; ll ans = 0;
     75     if (bj[o]) pushdown(o, l, r);
     76     if (ql <= mid) ans += query(lc, l, mid, ql, qr);
     77     if (qr > mid) ans += query(rc, mid + 1, r, ql, qr);
     78     return ans;
     79 }
     80 
     81 ll chain_query(int x, int y) {
     82     int fax = top[x], fay = top[y];
     83     ll ans = 0;
     84       while (fax != fay) {
     85           if (dep[fax] < dep[fay]) {
     86               swap(x, y);
     87               swap(fax, fay);
     88           }
     89         ans += query(1, 1, n, dfn[fax], dfn[x]);
     90         x = fa[fax];
     91         fax = top[x];
     92       }
     93       if (dep[x] > dep[y]) swap(x, y);
     94     ans += query(1, 1, n, dfn[x], dfn[y]);
     95     return ans;
     96 }
     97 
     98 int main() {
     99     n = read(); m = read();
    100       for (int i = 1; i <= n; ++ i) val[i] = read();
    101       for (int i = 1; i < n; ++ i) {
    102           int x = read(), y = read();
    103           ve[x].push_back(y);
    104           ve[y].push_back(x);
    105       }
    106     dfs1(1, 0);
    107     dfs2(1, 1);
    108     build(1, 1, n);
    109       while (m --) {
    110           int opt = read();
    111             if (opt == 1) { //单点加a 
    112                   int x = read(), a = read();
    113                   modify(1, 1, n, dfn[x], dfn[x], a);
    114             }
    115           else if (opt == 2) {
    116               int x = read(), a = read(); //所有子树加a 
    117               modify(1, 1, n, dfn[x], dfn[x] + size[x] - 1, a);
    118           }
    119           else {
    120               int x = read(); //询问点到根的点权和 
    121               printf("%lld
    ", chain_query(1, x));
    122           }
    123       }
    124     return 0;
    125 } 
  • 相关阅读:
    2-4安卓自学
    2-3安卓自学
    2-2安卓自学
    2-1安卓自学
    20210121 Sqlit数据库
    20210119 Sqlit数据库
    20210118 android学习
    20210117 android学习
    20210115 android学习
    20210114 android学习
  • 原文地址:https://www.cnblogs.com/Gaxc/p/9927148.html
Copyright © 2020-2023  润新知