版权声明:欢迎大家指正错误,有不同观点的欢迎评论,共同进步 https://blog.csdn.net/Sirius_han/article/details/82704673
Snacks HDU - 5692
题目链接
题意:n个点,n-1条边连接,使其形成一棵树;每个点有一个权值;m个询问:
0 x y:将x点的值改为y;
1 x :从0点出发,问经过x点的路径中能得到的最大全权值和是多少?
思路:m个询问首先就想到线段树;但是此题并不是线性问题,而是树形问题,所以想用线段树就要先把树转换成线性问题;问0点出发经过x点得到的最大权值其实就是0到x的距离dis[x]加上x到其某个子节点的最大值;改变x的值后,假设增加了val,就是x到其所有子节点的值都增加了val;由此可以看出,这其实是一个区间更新与询问;现在的问题就是怎样把其转换成线性问题;
这里就用到了dfs序;在dfs序中某节点x与其子节点是连续的,所以就可以将其转化为线性问题;
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
int n, m;
ll val[maxn];
struct node{
int v, nxt;
}edge[maxn<<1];
int head[maxn], cnt;
void add(int u, int v){
edge[cnt]=node{v, head[u]};
head[u]=cnt++;
}
ll dis[maxn];//dis[x]表示0点到x的距离;
int l[maxn], r[maxn], num;//l[x]表示在线段树中原先在树上为x的节点所能表示的最左边的点,r[x]就表示最右边的点,就是x的子节点的范围;
ll t[maxn];//t[j]表示线段树中边界为[j, j]的叶子表示的值;
void dfs(int u, int fa){
t[++num]=dis[u];
l[u]=num;
for(int i=head[u]; i!=-1; i=edge[i].nxt){
int v=edge[i].v;
if(v==fa) continue;
dis[v]=dis[u]+val[v];
dfs(v, u);
}
r[u]=num;
}
struct tree{
int l, r;
ll sum, lazy;
}tr[maxn<<2];
void pushup(int m){
tr[m].sum=max(tr[m<<1].sum, tr[m<<1|1].sum);
}
void pushdown(int m){
if(tr[m].lazy){
tr[m<<1].sum+=tr[m].lazy;
tr[m<<1|1].sum+=tr[m].lazy;
tr[m<<1].lazy+=tr[m].lazy;
tr[m<<1|1].lazy+=tr[m].lazy;
tr[m].lazy=0;
}
}
void build(int m, int l, int r){
tr[m].l=l;
tr[m].r=r;
tr[m].lazy=0;
if(l==r){
tr[m].sum=t[l];
return;
}
int mid=(l+r)>>1;
build(m<<1, l, mid);
build(m<<1|1, mid+1, r);
pushup(m);
}
void updata(int m, int l, int r, ll val){
if(tr[m].l==l&&tr[m].r==r){
tr[m].sum+=val;
tr[m].lazy+=val;
return;
}
pushdown(m);
int mid=(tr[m].l+tr[m].r)>>1;
if(r<=mid) updata(m<<1, l, r, val);
else if(l>mid) updata(m<<1|1, l, r, val);
else{
updata(m<<1, l, mid, val);
updata(m<<1|1, mid+1, r, val);
}
pushup(m);
}
ll query(int m, int l, int r){
if(tr[m].l==l&&tr[m].r==r){
return tr[m].sum;
}
pushdown(m);
int mid=(tr[m].l+tr[m].r)>>1;
ll temp;
if(r<=mid) temp=query(m<<1, l, r);
else if(l>mid) temp=query(m<<1|1, l, r);
else{
temp=max(query(m<<1, l, mid), query(m<<1|1, mid+1, r));
}
pushup(m);
return temp;
}
int main(){
int T, cas=0;
scanf("%d", &T);
while(T--){
scanf("%d%d", &n, &m);
memset(head, -1, sizeof(head));
cnt=0;
for(int i=1; i<n; i++){
int u, v;
scanf("%d%d", &u, &v);
add(u, v);
add(v, u);
}
for(int i=0; i<n; i++){
scanf("%lld", &val[i]);
}
num=0;
dis[0]=val[0];
dfs(0, 0);
build(1, 1, num);
printf("Case #%d:\n", ++cas);
while(m--){
int op, x;
ll y;
scanf("%d", &op);
if(op==0){
scanf("%d%lld", &x, &y);
updata(1, l[x], r[x], y-val[x]);
val[x]=y;
}
else{
scanf("%d", &x);
printf("%lld\n", query(1, l[x], r[x]));
}
}
}
return 0;
}