http://bestcoder.hdu.edu.cn/contests/contest_showproblem.php?cid=701&pid=1003
http://acm.hdu.edu.cn/showproblem.php?pid=5692
Problem Description
百度科技园内有n个零食机,零食机之间通过n−1条路相互连通。每个零食机都有一个值v,表示为小度熊提供零食的价值。
由于零食被频繁的消耗和补充,零食机的价值v会时常发生变化。小度熊只能从编号为0的零食机出发,并且每个零食机至多经过一次。另外,小度熊会对某个零食机的零食有所偏爱,要求路线上必须有那个零食机。
为小度熊规划一个路线,使得路线上的价值总和最大。
Input
输入数据第一行是一个整数T(T≤10),表示有T组测试数据。
对于每组数据,包含两个整数n,m(1≤n,m≤100000),表示有n个零食机,m次操作。
接下来n−1行,每行两个整数x和y(0≤x,y<n),表示编号为x的零食机与编号为y的零食机相连。
接下来一行由n个数组成,表示从编号为0到编号n−1的零食机的初始价值v(∣v∣<100000)。
接下来m行,有两种操作:0 x y,表示编号为x的零食机的价值变为y;1 x,表示询问从编号为0的零食机出发,必须经过编号为x零食机的路线中,价值总和的最大值。
本题可能栈溢出,辛苦同学们提交语言选择c++,并在代码的第一行加上:
#pragma comment(linker, "/STACK:1024000000,1024000000")
Output
对于每组数据,首先输出一行”Case #?:”,在问号处应填入当前数据的组数,组数从1开始计算。
对于每次询问,输出从编号为0的零食机出发,必须经过编号为x零食机的路线中,价值总和的最大值。
Sample Input
1
6 5
0 1
1 2
0 3
3 4
5 3
7 -5 100 20 -5 -7
1 1
1 3
0 2 -1
1 1
1 5
Sample Output
Case #1:
102
27
2
20
Solution
将树按照 dfs 序展开,那么询问 1 x 就是一段区间内的点,离 0 的距离的最大值。可以考虑区间最值查询的相关数据结构。
对于更改点权的操作,将其变成增加点权的操作,那么也就是带区间更新的区间最值查询,到此可以用线段树解决该题。
另外,可以一开始建立点权全部为 0 的树,然后更新添加点权,精简代码。
Code
- #pragma comment(linker, "/STACK:1024000000,1024000000")
- #include <stdio.h>
- #include <string.h>
- #include <stdlib.h>
-
- #include <algorithm>
- #include <vector>
-
- const int N = 100000 + 10;
-
- std::vector<std::vector<int> > g;
-
- int dfsl[N];
- int dfsr[N];
-
- void dfs(int u, int f, int& timestamp)
- {
- dfsl[u] = ++timestamp;
- for (int i = 0; i < (int) g[u].size(); ++i) {
- int v = g[u][i];
- if (v == f) {
- continue;
- }
- dfs(v, u, timestamp);
- }
- dfsr[u] = timestamp;
- }
-
- struct segment_tree_t
- {
- #define ID ((l + r) | (l != r))
- #define IDL ((l + m) | (l != m))
- #define IDR ((m+1 + r) | (m+1 != r))
- #define LSON l, m
- #define RSON m+1, r
-
- struct tree_node
- {
- long long maxlen;
- long long flag;
-
- void add(long long x)
- {
- maxlen += x;
- flag += x;
- }
- } tree[N << 1];
-
- void build(int l, int r)
- {
- tree[ID].maxlen = tree[ID].flag = 0;
- if (l == r) {
- return;
- }
- int m = (l + r) >> 1;
- build(LSON); build(RSON);
- }
-
- void pushdown(int l, int r)
- {
- int m = (l + r) >> 1;
- long long& flag = tree[ID].flag;
- if (flag != 0) {
- tree[IDL].add(flag);
- tree[IDR].add(flag);
- flag = 0;
- }
- }
-
- void pushup(int l, int r)
- {
- int m = (l + r) >> 1;
- tree[ID].maxlen = std::max(tree[IDL].maxlen, tree[IDR].maxlen);
- }
-
- void update(int l, int r, int x, int y, int add)
- {
- if (l == x && r == y) {
- tree[ID].add(add);
- return;
- }
-
- int m = (l + r) >> 1;
- pushdown(l, r);
- if (y <= m) {
- update(LSON, x, y, add);
- }
- else if (x > m) {
- update(RSON, x, y, add);
- }
- else {
- update(LSON, x, m, add);
- update(RSON, m+1, y, add);
- }
- pushup(l, r);
- }
-
- long long query(int l, int r, int x, int y)
- {
- if (l == x && r == y) {
- return tree[ID].maxlen;
- }
-
- int m = (l + r) >> 1;
- pushdown(l, r);
- if (y <= m) {
- return query(LSON, x, y);
- }
- else if (x > m) {
- return query(RSON, x, y);
- }
- else {
- return std::max(query(LSON, x, m), query(RSON, m+1, y));
- }
- }
- } st;
-
- int a[N];
-
- void task(int casi)
- {
- printf("Case #%d:\n", casi);
-
- int n, m;
- scanf("%d %d", &n, &m);
- g.clear();
- g.resize(n);
- for (int i = 1; i < n; ++i) {
- int u, v;
- scanf("%d %d", &u, &v);
- g[u].push_back(v);
- g[v].push_back(u);
- }
-
- int timestamp = 0;
- dfs(0, -1, timestamp);
-
- st.build(1, n);
- for (int i = 0; i < n; ++i) {
- scanf("%d", a+i);
- st.update(1, n, dfsl[i], dfsr[i], a[i]);
- }
- for (int mi = 1; mi <= m; ++mi) {
- int cmd;
- int x, y;
- scanf("%d", &cmd);
- if (cmd == 0) {
- scanf("%d %d", &x, &y);
- y -= a[x];
- st.update(1, n, dfsl[x], dfsr[x], y);
- a[x] += y;
- }
- else {
- scanf("%d", &x);
- printf("%I64d\n", st.query(1, n, dfsl[x], dfsr[x]));
- }
- }
- }
-
- int main()
- {
- int casc;
- scanf("%d", &casc);
- for (int casi = 1; casi <= casc; ++casi) {
- task(casi);
- }
- return 0;
- }