zoukankan      html  css  js  c++  java
  • [bzoj3306]树——树上倍增+dfs序+线段树

    Brief Description

    您需要写一种数据结构,支持:

    1. 更改一个点的点权
    2. 求一个子树的最小点权
    3. 换根

    Algorithm Design

    我们先忽略第三个要求。
    看到要求子树的最小点权,我们想到使用dfs序。容易看到,一个节点的子树在dfs序中的范围就是([l(x),r(x)]),所以我们把树结构变成了线性结构,从而变成了一个RMQ问题,我们使用线段树即可求解。
    对于换根,我们不必重新求出拓扑结构。我们考察换根会影响到的节点。对于新根的子树中的节点,一定没有影响,对于不是新根祖先的节点,一定也没有影响。所以我们只考虑新根的祖先。
    我们可以看出,换成新根以后,祖先的覆盖范围就变成了全树抛去新根到祖先路径上距离祖先距离最近的节点的子树大小,设这个点为y,那么dfs序中的范围就是([1,l[y]-1] cup [r[y]+1, n])
    所以问题就变成了如何求树上离某个点距离最近的儿子。显然可以使用树上倍增来求。

    Code

    #include <algorithm>
    #include <cstdio>
    using std::max;
    using std::min;
    const int maxn = 100010;
    int q[maxn], ind = 0, l[maxn], r[maxn], n, m, root, val[maxn], deep[maxn],
                 fa[maxn][20];
    int cnt = 0;
    struct edge {
      int to, next;
    } e[maxn];
    int last[maxn];
    struct seg {
      int l, r, mn;
    } t[maxn << 2];
    void insert(int x, int y) {
      e[++cnt].to = y;
      e[cnt].next = last[x];
      last[x] = cnt;
    }
    void update(int k) { t[k].mn = min(t[k << 1].mn, t[k << 1 | 1].mn); }
    void dfs(int x) {
      l[x] = ++ind;
      q[ind] = x;
      for (int i = 1; i <= 16; i++) {
        if (deep[x] < (1 << i))
          break;
        fa[x][i] = fa[fa[x][i - 1]][i - 1];
      }
      for (int i = last[x]; i; i = e[i].next) {
        fa[e[i].to][0] = x;
        deep[e[i].to] = deep[x] + 1;
        dfs(e[i].to);
      }
      r[x] = ind;
    }
    void build(int k, int l, int r) {
      t[k].l = l, t[k].r = r;
      int mid = (l + r) >> 1;
      if (l == r) {
        t[k].mn = val[q[l]];
        return;
      }
      build(k << 1, l, mid);
      build(k << 1 | 1, mid + 1, r);
      t[k].mn = min(t[k << 1].mn, t[k << 1 | 1].mn);
    }
    void modify(int k, int pos, int val) {
      int l = t[k].l, r = t[k].r, mid = (l + r) >> 1;
      if (l == r) {
        t[k].mn = val;
        return;
      }
      if (pos <= mid)
        modify(k << 1, pos, val);
      else
        modify(k << 1 | 1, pos, val);
      update(k);
    }
    int query(int k, int x, int y) {
      int l = t[k].l, r = t[k].r, mid = (l + r) >> 1;
      if (x <= l && r <= y)
        return t[k].mn;
      int ans = 0x3f3f3f;
      if (x <= mid)
        ans = min(ans, query(k << 1, x, y));
      if (y > mid)
        ans = min(ans, query(k << 1 | 1, x, y));
      return ans;
    }
    int main() {
    #ifndef ONLINE_JUDGE
      freopen("input", "r", stdin);
    #endif
      scanf("%d %d", &n, &m);
      for (int i = 1; i <= n; i++) {
        int f;
        scanf("%d %d", &f, &val[i]);
        if (f)
          insert(f, i);
      }
      dfs(root = 1);
    #ifndef ONLINE_JUDGE
      for (int i = 1; i <= ind; i++)
        printf("%d ", q[i]);
      printf("
    ");
    #endif
      build(1, 1, n);
      while (m--) {
        char ch[5];
        int x;
        scanf("%s %d", ch, &x);
        if (ch[0] == 'V') {
          int val;
          scanf("%d", &val);
          modify(1, l[x], val);
        } else if (ch[0] == 'E')
          root = x;
        else {
          if (root == x)
            printf("%d
    ", t[1].mn);
          else if (l[x] <= l[root] && r[x] >= r[root]) { // x is the father of root
            int y = root, d = deep[y] - deep[x] - 1;
            for (int i = 0; i <= 16; i++)
              if (d & (1 << i))
                y = fa[y][i];
            printf("%d
    ", min(query(1, 1, l[y] - 1), query(1, r[y] + 1, n)));
          } else
            printf("%d
    ", query(1, l[x], r[x]));
        }
      }
      return 0;
    }
    
  • 相关阅读:
    Java的静态块与实例块(转)
    Programming Ability Test学习 1031. Hello World for U (20)
    Programming Ability Test学习 1011. World Cup Betting (20)
    Programming Ability Test学习 1027. Colors in Mars (20)
    Programming Ability Test学习 1064. Complete Binary Search Tree (30)
    Programming Ability Test学习 1008. Elevator (20)
    【maven详解-生命周期】Maven的生命周期和插件
    【maven详解-插件】maven插件学习之源码插件Source Xref
    $(document).ready(){}、$(fucntion(){})、(function(){})(jQuery)onload()的区别
    你还没真的努力过,就轻易输给了懒惰
  • 原文地址:https://www.cnblogs.com/gengchen/p/6514016.html
Copyright © 2011-2022 走看看