1. 程式人生 > >Snacks HDU - 5692 (線段樹+dfs序)

Snacks HDU - 5692 (線段樹+dfs序)

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; }