HDU 5692 Snacks (百度之星2A)

本文介绍了一种利用DFS序将树形结构转化为线性序列的方法,并通过线段树实现区间修改与查询最值操作,有效解决特定类型的树上问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

分析:

题意就是根节点到 i 子树上所有点的最大值,并且这棵树上的点权可修改。
那么维护所有点到根的和,如果修改一个u节点,只会改变根到 u 子树上点的和。把树用dfs序遍历一下,把树变成一个序列,修改节点就变成了序列的区间修改,找最大值也变成了区间找最值。一棵线段树搞定了。
复杂度: o(mlogn)

代码:

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <set>
#include <map>
#include <queue>
#include <vector>
#include <string>

using namespace std;

typedef long long LL;
typedef vector <int>    VI;
typedef pair <int,int>  PII;
#define FOR(i,x,y)  for(int i = x;i < y;++ i)
#define IFOR(i,x,y) for(int i = x;i > y;-- i)
#define pb  push_back
#define mp  make_pair
#define fi  first
#define se  second
#define lrt rt<<1
#define rrt rt<<1|1
#define lson    rt<<1,l,mid
#define rson    rt<<1|1,mid+1,r

const int maxn = 200010;
VI  mat[maxn];
LL a[maxn],suf[maxn],w[maxn];
int n,m;

int tot,dfn[maxn],s[maxn],t[maxn];

void dfs(int u,int fa){
    if(fa == -1)    suf[u] = a[u];
    else    suf[u] = a[u]+suf[fa];
    dfn[++tot] = u; s[u] = tot; w[tot] = suf[u];
    FOR(i,0,(int)mat[u].size()){
        int v = mat[u][i];
        if(v == fa) continue;
        dfs(v,u);
    }
    dfn[++tot] = u; t[u] = tot; w[tot] = suf[u];
}

struct Tree{
    int l,r;
    LL val,lazy;
}tree[maxn<<2];

void pushup(int rt){
    tree[rt].val = max(tree[lrt].val,tree[rrt].val);
}

void pushdown(int rt){
    if(tree[rt].lazy){
        tree[lrt].val += tree[rt].lazy;
        tree[rrt].val += tree[rt].lazy;
        tree[lrt].lazy += tree[rt].lazy;
        tree[rrt].lazy += tree[rt].lazy;
        tree[rt].lazy = 0;
    }
}

void build(int rt,int l,int r){
    tree[rt].l = l; tree[rt].r = r;
    tree[rt].lazy = 0;
    if(l == r){
        tree[rt].val = w[l];
        return;
    }
    int mid = (l+r)>>1;
    build(lson);
    build(rson);
    pushup(rt);
}

void modify(int rt,int l,int r,int lazy){
    if(tree[rt].l == l && tree[rt].r == r){
        tree[rt].val += lazy;
        tree[rt].lazy += lazy;
        return;
    }
    pushdown(rt);
    int mid = (tree[rt].l+tree[rt].r)>>1;
    if(r <= mid)    modify(lrt,l,r,lazy);
    else if(l > mid)    modify(rrt,l,r,lazy);
    else{
        modify(lson,lazy);
        modify(rson,lazy);
    }
    pushup(rt);
}

LL query(int rt,int l,int r){
    if(l == tree[rt].l && r == tree[rt].r)  return tree[rt].val;
    pushdown(rt);
    int mid = (tree[rt].l+tree[rt].r)>>1;
    if(r <= mid)    return query(lrt,l,r);
    else    if(l > mid) return query(rrt,l,r);
    else    return max(query(lson),query(rson));
}

void work(){
    tot = 0;    dfs(0,-1);
    build(1,1,tot);
    FOR(i,0,m){
        int cmd,x,y;
        scanf("%d",&cmd);
        if(cmd){
            scanf("%d",&x);
            printf("%I64d\n",query(1,s[x],t[x]));
        }
        else{
            scanf("%d%d",&x,&y);
            modify(1,s[x],t[x],y-a[x]);
            a[x] = y;
        }
    }
}

int main(){
    int T,tCase = 0;    scanf("%d",&T);
    while(T--){
        printf("Case #%d:\n",++tCase);
        scanf("%d%d",&n,&m);
        FOR(i,0,maxn)   mat[i].clear();
        int u,v;
        FOR(i,1,n)  scanf("%d%d",&u,&v),mat[u].pb(v),mat[v].pb(u);
        FOR(i,0,n)  scanf("%I64d",&a[i]);
        work();
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值