Snacks HDU - 5692 (線段樹+dfs序)
阿新 • • 發佈:2018-12-01
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;
}