HDU5692 dfs + 线段树维护区间最大值
先附上题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5692
Problem Description
百度科技园内有n个零食机,零食机之间通过n−1条路相互连通。每个零食机都有一个值v,表示为小度熊提供零食的价值。
由于零食被频繁的消耗和补充,零食机的价值v会时常发生变化。小度熊只能从编号为0的零食机出发,并且每个零食机至多经过一次。另外,小度熊会对某个零食机的零食有所偏爱,要求路线上必须有那个零食机。
为小度熊规划一个路线,使得路线上的价值总和最大。
由于零食被频繁的消耗和补充,零食机的价值v会时常发生变化。小度熊只能从编号为0的零食机出发,并且每个零食机至多经过一次。另外,小度熊会对某个零食机的零食有所偏爱,要求路线上必须有那个零食机。
为小度熊规划一个路线,使得路线上的价值总和最大。
分析:我们可以利用后序遍历将树上的每个节点编号, 这样的话一个顶点的叶子结点肯定在他的前面, 我们用l[x] r[x]表示x以及x的所有叶子结点,这样对于1 x的查询我们只需要找出l[x] r[x]区间的最大值即可, 对于0 x y我们只需要调整l[x] r[x]区间的值即可, 因为调整了一个顶点的点权之后只影响该点以及该点的叶子结点的权值。代码如下:
#include <cstdio> #include <cstring> #include <algorithm> #include <vector> #include <iostream> using namespace std; typedef long long LL; const int maxn = 100000 + 100; int n, m; vector<int> tree[maxn]; int node_weight[maxn]; LL num[maxn]; int l[maxn], r[maxn], nlr; struct Segment { int l, r; LL x; LL lazy; }seg[3*maxn]; void build(int rt, int l, int r) { seg[rt].l = l; seg[rt].r = r; if(l == r) { seg[rt].x = num[l]; seg[rt].lazy = 0; return ; } build(2*rt, l, (l+r)/2); build(2*rt+1, (l+r)/2+1, r); seg[rt].x = max(seg[2*rt].x, seg[2*rt+1].x); seg[rt].lazy = 0; } void push_down(int rt) { if(seg[rt].lazy != 0){ int chl = 2*rt; seg[chl].x += seg[rt].lazy; seg[chl].lazy += seg[rt].lazy; int chr = 2*rt + 1; seg[chr].x += seg[rt].lazy; seg[chr].lazy += seg[rt].lazy; seg[rt].lazy = 0; } } void push_up(int rt) { seg[rt].x = max(seg[2*rt].x, seg[2*rt+1].x); } LL query(int rt, int l, int r) { //查询区间l - r的最大值 if(seg[rt].l == l && seg[rt].r == r) { return seg[rt].x; } push_down(rt); int mid = (seg[rt].l + seg[rt].r)/2; if(r <= mid) return query(2*rt, l, r); else if(l > mid) return query(2*rt+1, l, r); else { LL v1 = query(2*rt, l, mid); LL v2 = query(2*rt+1, mid+1, r); return max(v1, v2); } } void update(int rt, int l, int r, int c) { // 区间l-r增加C if(seg[rt].l == l && seg[rt].r == r) { seg[rt].x += c; seg[rt].lazy += c; return ; } push_down(rt); int mid = (seg[rt].l + seg[rt].r)/2; if(r <= mid) update(2*rt, l, r, c); else if(l > mid) update(2*rt+1, l, r, c); else { update(2*rt, l, mid, c); update(2*rt+1, mid+1, r, c); } push_up(rt); } void dfs(int pre, int u, int &k, LL sum) { l[u] = 2*maxn; int son = 0; sum += node_weight[u]; for(int i=0; i<tree[u].size(); i++) { int v = tree[u][i]; if(v == pre) continue; son++; dfs(u, v, k, sum); l[u] = min(l[u], l[v]); } num[k] = sum; r[u] = k++; // printf("%d ", u); //////////////////////////// if(son == 0) l[u] = r[u]; } int main() { int T; scanf("%d", &T); int kase = 0; while(T--) { scanf("%d%d", &n, &m); for(int i=0; i<n; i++) tree[i].clear(); for(int i=0; i<n-1; i++) { int u, v; scanf("%d%d", &u, &v); tree[u].push_back(v); tree[v].push_back(u); } for(int i=0; i<n; i++) scanf("%d", &node_weight[i]); nlr = 0; dfs(-1, 0, nlr, 0); // printf("\n"); ////////////////////////////////// // for(int i=0; i<n; i++) // printf("l[%d] = %d, r[%d] = %d\n", i, l[i], i, r[i]); build(1, 0, nlr-1); printf("Case #%d:\n", ++kase); for(int i=0; i<m; i++) { int op; scanf("%d", &op); if(op == 0) { int x, y; scanf("%d%d", &x, &y); update(1, l[x], r[x], y-node_weight[x]); node_weight[x] = y; }else{ int x; scanf("%d", &x); LL res = query(1, l[x], r[x]); cout<<res<<endl; } } } return 0; }