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\n", 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\n", ans);
      } else {
        update(id[u], v, 1, n, 1);
      }
    }
  }
  return 0;
}

  

posted @ 2017-12-21 14:46  Fighting_Heart  阅读(218)  评论(0编辑  收藏  举报