传送门
题目描述
百度科技园内有n个零食机,零食机之间通过n−1条路相互连通。每个零食机都有一个值v,表示为小度熊提供零食的价值。
由于零食被频繁的消耗和补充,零食机的价值v会时常发生变化。小度熊只能从编号为0的零食机出发,并且每个零食机至多经过一次。另外,小度熊会对某个零食机的零食有所偏爱,要求路线上必须有那个零食机。
为小度熊规划一个路线,使得路线上的价值总和最大。
分析
这道题我们可以把树形结构去转换成链式结构,去维护从跟节点到每一个节点的距离,然后用线段去去维护区间最值,修改一个点的价值,其实就是对这个点以及这个点的子树进行修改,也就转换成了区间修改,所以我们可以用dfs去把这棵树转换成链,然后用线段树做到区间查询和修改
代码
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <queue>
#include <cstring>
#define debug(x) cout<<#x<<":"<<x<<endl;
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> PII;
const ll INF = 0x3f3f3f3f3f3f;
const int N = 100010;
int h[N],ne[N * 2],e[N * 2],idx;
ll d[N],s[N];
int in[N],out[N];
int n,m;
int cnt;
struct Node{
int l,r;
ll sum,add;
}tr[N << 2];
void add(int x,int y){
ne[idx] = h[x],e[idx] = y,h[x] = idx++;
}
void dfs(int u,int fa,ll pp){
in[u] = ++cnt;
d[cnt] = pp;
for(int i = h[u];~i;i = ne[i]){
int j = e[i];
if(j == fa) continue;
dfs(j,u,pp + s[j]);
}
out[u] = cnt;
}
void pushup(int u){
tr[u].sum = max(tr[u << 1].sum,tr[u << 1 | 1].sum);
}
void down(int u){
auto &f = tr[u],&l = tr[u << 1],&r = tr[u << 1 | 1];
if(f.add){
l.add += f.add,l.sum += f.add;
r.add += f.add,r.sum += f.add;
f.add = 0;
}
}
void build(int u,int l,int r){
tr[u].l = l,tr[u].r = r,tr[u].add = 0;
if(l == r){
tr[u].sum = d[l];
return;
}
int mid = l + r >> 1;
build(u << 1,l,mid);
build(u << 1 | 1,mid + 1,r);
pushup(u);
}
void modify(int u,int l,int r,ll x){
if(tr[u].l >= l && tr[u].r <= r){
tr[u].sum += x;
tr[u].add += x;
return;
}
down(u);
int mid = tr[u].l + tr[u].r >> 1;
if(l <= mid) modify(u << 1,l,r,x);
if(r > mid) modify(u << 1 | 1,l,r,x);
pushup(u);
}
ll query(int u,int l,int r){
if(tr[u].l >= l && tr[u].r <= r){
return tr[u].sum;
}
down(u);
int mid = tr[u].l + tr[u].r >> 1;
ll ans = -INF;
if(l <= mid) ans = query(u << 1,l,r);
if(r > mid) ans = max(query(u << 1 | 1,l,r),ans);
return ans;
}
int main(){
int t;
scanf("%d",&t);
for(int ppp = 1;ppp <= t;ppp++){
memset(h,-1,sizeof h);
idx = cnt = 0;
scanf("%d%d",&n,&m);
printf("Case #%d:\n",ppp);
for(int i = 1;i < n;i++){
int x,y;
scanf("%d%d",&x,&y);
add(x,y),add(y,x);
}
for(int i = 0;i < n;i++) scanf("%lld",&s[i]);
dfs(0,-1,s[0]);
build(1,1,n);
while(m--){
int op,x,y;
scanf("%d%d",&op,&x);
if(!op){
scanf("%d",&y);
ll add = 1ll * y - s[x];
modify(1,in[x],out[x],add);
s[x] = y;
}
else printf("%lld\n",query(1,in[x],out[x]));
}
}
}