Snacks HDU - 5692 (线段树+dfs序)

版权声明:欢迎大家指正错误,有不同观点的欢迎评论,共同进步 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;
}

猜你喜欢

转载自blog.csdn.net/Sirius_han/article/details/82704673