• 2017年浙江中医药大学大学生程序设计竞赛(重现赛)A


    题目描述

    kotomi 有一棵树。树上有n个房子,编号1-n,每个房子有一个快乐值。
    kotomi想知道从a房子到b房子路径上的最大快乐值或者路径山疙瘩快乐值的和。
    并且kotomi可以改变任意一个房子的快乐值。
    具体如下
    (1) 0 a b:查询a到b路径上的最大快乐值(包含a和b)
    (2) 1 a b:查询a到b路径上的所有房子快乐值的和。(包含a和b)
    (3) 2 x y:将编号为x的房子的快乐值改为y。
     

    输入描述:

    多组测试数据
    第一行有两个整数n,q。表示有n个房子,q次操作。
    第二行有n个整数v1,v2...vn,表示编号为i的房子的快乐值vi
    接下来n-1行,每行两个整数u,v,表示编号为u和编号为v的房子之间有一条直接路径。
    接下来p行,每行开头一个整数(0,1或2)表述操作类型,每个操作后有两个整数。
     

    输出描述:

    对于操作为0和1的输出对应的值。
    示例1

    输入

    6 10
    2 5 9 10 36 5
    1 2
    1 3
    1 4
    2 5
    2 6
    0 1 4
    0 1 6
    1 5 6
    1 3 6
    1 6 3
    2 3 10
    1 5 3
    0 4 5
    2 5 100
    1 5 4

    输出

    10
    5
    46
    21
    21
    53
    36
    117

    题解

    裸的树链剖分。

    #include <bits/stdc++.h>
    using namespace std;
    
    const int maxn = 200000 + 10;
    int n, q, v[maxn];
    
    int h[maxn], to[maxn], nx[maxn], cnt;
    int dep[maxn], son[maxn], top[maxn], sz[maxn], fa[maxn], id[maxn], fid[maxn];
    int tot;
    
    int sum[maxn * 4];
    int mx[maxn * 4];
    
    void add(int u, int v) {
      to[cnt] = v;
      nx[cnt] = h[u];
      h[u] = cnt ++;
    }
    
    void dfs1(int x, int y, int d) {
      dep[x] = d;
      sz[x] = 1;
      fa[x] = y;
      for(int i = h[x]; i != -1; i = nx[i]) {
        if(dep[to[i]]) continue;
        dfs1(to[i], x, d + 1);
        sz[x] = sz[x] + sz[to[i]];
        if(sz[to[i]] > sz[son[x]]) son[x] = to[i];
      }
    }
    
    void dfs2(int x) {
      if(son[x]) {
        top[son[x]] = top[x];
        id[son[x]] = ++ tot;
        fid[tot] = son[x];
        dfs2(son[x]);
      }
      for(int i = h[x]; i != -1; i = nx[i]) {
        if(top[to[i]]) continue;
        if(to[i] == son[x]) continue;
        top[to[i]] = to[i];
        id[to[i]] = ++ tot;
        fid[tot] = to[i];
        dfs2(to[i]);
      }
    }
    
    void pushUp(int rt) {
      mx[rt] = max(mx[2 * rt], mx[2 * rt + 1]);
      sum[rt] = sum[2 * rt] + sum[2 * rt + 1];
    }
    
    void build(int l, int r, int rt) {
      if(l == r) {
        sum[rt] = v[fid[l]];
        mx[rt] = v[fid[l]];
        return;
      }
      int mid = (l + r) / 2;
      build(l, mid, 2 * rt);
      build(mid + 1, r, 2 * rt + 1);
      pushUp(rt);
    }
    
    void update(int pos, int val, int l, int r, int rt) {
      if(l == r) {
        sum[rt] = val;
        mx[rt] = val;
        return;
      }
      int mid = (l + r) / 2;
      if(pos <= mid) update(pos, val, l, mid, 2 * rt);
      else update(pos, val, mid + 1, r, 2 * rt + 1);
      pushUp(rt);
    }
    
    int getsum(int L, int R, int l, int r, int rt) {
      if(L <= l && r <= R) {
        return sum[rt];
      }
      int mid = (l + r) / 2;
      int left = 0;
      int right = 0;
      if(L <= mid) left = getsum(L, R, l, mid, 2 * rt);
      if(R > mid) right = getsum(L, R, mid + 1, r, 2 * rt + 1);
      return left + right;
    }
    
    int getmax(int L, int R, int l, int r, int rt) {
      if(L <= l && r <= R) {
        return mx[rt];
      }
      int mid = (l + r) / 2;
      int left = -50000;
      int right = -50000;
      if(L <= mid) left = getmax(L, R, l, mid, 2 * rt);
      if(R > mid) right = getmax(L, R, mid + 1, r, 2 * rt + 1);
      return max(left, right);
    }
    
    int main() {
      while(~scanf("%d%d", &n, &q)) {
        for(int i = 1; i <= n; i ++) {
          scanf("%d", &v[i]);
          h[i] = -1;
        }
        for(int i = 0; i <= n; i ++) {
          dep[i] = 0;
          sz[i] = 0;
          son[i] = 0;
          top[i] = 0;
        }
        tot = cnt = 0;
        for(int i = 1; i <= n - 1; i ++) {
          int u, v;
          scanf("%d%d", &u, &v);
          add(u, v);
          add(v, u);
        }
        dfs1(1, -1, 1);
    
        tot = 0;
        top[1] = 1;
        id[1] = ++ tot;
        fid[tot] = 1;
        dfs2(1);
    
        build(1, n, 1);
    
        while(q --) {
          int op, u, v;
          scanf("%d%d%d", &op, &u, &v);
          if(op == 0) {
            int ans = -50000;
            while(1) {
              int f1 = top[u], f2 = top[v];
              if(f1 != f2) {
                if(dep[f1] >= dep[f2]) {
                  ans = max(ans, getmax(min(id[u], id[f1]), max(id[u], id[f1]), 1, n, 1));
                  u = fa[f1];
                } else {
                  ans = max(ans, getmax(min(id[v], id[f2]), max(id[v], id[f2]), 1, n, 1));
                  v = fa[f2];
                }
              } else {
                ans = max(ans, getmax(min(id[u], id[v]), max(id[u], id[v]), 1, n, 1));
                break;
              }
            }
            printf("%d
    ", ans);
          } else if(op == 1) {
            int ans = 0;
            while(1) {
              int f1 = top[u], f2 = top[v];
              if(f1 != f2) {
                if(dep[f1] >= dep[f2]) {
                  ans = ans + getsum(min(id[u], id[f1]), max(id[u], id[f1]), 1, n, 1);
                  u = fa[f1];
                } else {
                  ans = ans + getsum(min(id[v], id[f2]), max(id[v], id[f2]), 1, n, 1);
                  v = fa[f2];
                }
              } else {
                ans = ans + getsum(min(id[u], id[v]), max(id[u], id[v]), 1, n, 1);
                break;
              }
            }
            printf("%d
    ", ans);
          } else {
            update(id[u], v, 1, n, 1);
          }
        }
      }
      return 0;
    }
    

      

  • 相关阅读:
    iOS新手在引入第三方出现的几个小问题
    XMPP安装中遇到需要卸载openfire的步骤
    KVC
    SQLite错误码
    简单对象的本地化(以图片为例)
    使用MD5完成自定义Person对象的加密过程
    IOS--工作总结--post上传文件(以流的方式上传)
    IOS开发系列 --- 核心动画
    监听键盘 防止输入时覆盖掉textfiled
    比较选择的开始时间和结束时间的大小
  • 原文地址:https://www.cnblogs.com/zufezzt/p/8080542.html
Copyright © 2020-2023  润新知