HDU 5692 (线段树 dfs序)

Snacks

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 215    Accepted Submission(s): 48


Problem Description
百度科技园内有 n 个零食机,零食机之间通过 n1 条路相互连通。每个零食机都有一个值 v ,表示为小度熊提供零食的价值。

由于零食被频繁的消耗和补充,零食机的价值 v 会时常发生变化。小度熊只能从编号为0的零食机出发,并且每个零食机至多经过一次。另外,小度熊会对某个零食机的零食有所偏爱,要求路线上必须有那个零食机。

为小度熊规划一个路线,使得路线上的价值总和最大。
 

Input
输入数据第一行是一个整数 T(T10) ,表示有 T 组测试数据。

对于每组数据,包含两个整数 n,m(1n,m100000) ,表示有 n 个零食机, m 次操作。

接下来 n1 行,每行两个整数 x y(0x,y<n) ,表示编号为 x 的零食机与编号为 y 的零食机相连。

接下来一行由 n 个数组成,表示从编号为0到编号为 n1 的零食机的初始价值 v(|v|<100000)

接下来 m 行,有两种操作: 0 x y ,表示编号为 x 的零食机的价值变为 y 1 x ,表示询问从编号为0的零食机出发,必须经过编号为 x 零食机的路线中,价值总和的最大值。

本题可能栈溢出,辛苦同学们提交语言选择c++,并在代码的第一行加上:

`#pragma comment(linker, "/STACK:1024000000,1024000000") `
 

Output
对于每组数据,首先输出一行”Case #?:”,在问号处应填入当前数据的组数,组数从1开始计算。

对于每次询问,输出从编号为0的零食机出发,必须经过编号为 x 零食机的路线中,价值总和的最大值。
 

Sample Input
  
  
1 6 5 0 1 1 2 0 3 3 4 5 3 7 -5 100 20 -5 -7 1 1 1 3 0 2 -1 1 1 1 5
 

Sample Output
  
  
Case #1: 102 27 2 20
 


对于每一个节点,改变它的权值只影响根节点到他的子树所有节点的路径权值,

所以给每一节点确定一个dfs序,l[u]表示他的子树叶子中最小的dfs序,r[u]就表示

自己的dfs序,这样每次修改一个节点就相当于修改l[u]~r[u]之间的路径权值,

然后敲一棵线段树维护下最大值就好了.

#include <cstring>
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <cmath>
#include <map>
#include <queue>
#include <set>
using namespace std;
#define maxn 111111
#define pl c<<1
#define pr (c<<1)|1
#define lson tree[c].l,tree[c].mid,pl
#define rson tree[c].mid+1,tree[c].r,pr

struct node {
    int l, r, mid;
    long long sum, Max, add;
}tree[maxn<<4];
struct E {
    int v, next;
}edge[maxn<<1];
int head[maxn], cnt;
int n, m;

void add_edge (int u, int v) {
    edge[cnt].v = v, edge[cnt].next = head[u], head[u] = cnt++;
}

long long gg[maxn];
int index;
long long val[maxn];
int l[maxn], r[maxn];

void push_up (int c) {
    if (tree[c].l == tree[c].r)
        return ;
    tree[c].Max = max (tree[pl].Max, tree[pr].Max);
    return ;
}

void push_down (int c) {
    if (tree[c].l == tree[c].r)
        return ;
    tree[pl].Max += tree[c].add, tree[pr].Max += tree[c].add;
    tree[pl].sum += tree[c].add, tree[pr].sum += tree[c].add;
    tree[pl].add += tree[c].add, tree[pr].add += tree[c].add;
    tree[c].add = 0;
}

void build_tree (int l, int r, int c) {
    tree[c].l = l, tree[c].r = r, tree[c].mid = (l+r)>>1;
    tree[c].add = 0;
    if (l == r) {
        tree[c].sum = tree[c].Max = gg[l];
        return ;
    }
    build_tree (lson);
    build_tree (rson);
    push_up (c);
}

void update (int l, int r, int c, int x, int y, int val) {
    if (tree[c].add)
        push_down (c);
    if (l == x && y == r) {
        tree[c].Max += val;
        tree[c].sum += val;
        tree[c].add += val;
        return ;
    }
    if (tree[c].mid >= y)
        update (lson, x, y, val);
    else if (tree[c].mid < x)
        update (rson, x, y, val);
    else {
        update (lson, x, tree[c].mid, val);
        update (rson, tree[c].mid+1, y, val);
    }
    push_up (c);
}

long long query (int l, int r, int c, int x, int y) {
    if (tree[c].add)
        push_down (c);
    if (l == x && y == r) {
        return tree[c].Max;
    }
    if (tree[c].mid >= y)
        return query (lson, x, y);
    else if (tree[c].mid < x)
        return query (rson, x, y);
    else
        return max (query (lson, x, tree[c].mid), query (rson, tree[c].mid+1, y));
}

void dfs (int u, int fa, long long sum) {
//当前节点 父亲 路径权值和
    sum += val[u];
    l[u] = 1000000;
    int son = 0;
    for (int i = head[u]; i != -1; i = edge[i].next) {
        int v = edge[i].v;
        if (v == fa)
            continue;
        son++;
        dfs (v, u, sum);
        l[u] = min (l[u], l[v]);
    }
    r[u] = ++index;
    gg[index] = sum;
    if (son == 0) {
        l[u] = r[u];
    }
}

void work (int n) {
    build_tree (1, n, 1);
    while (m--) {
        int op;
        scanf ("%d", &op);
        if (op == 1) {
            int u;
            scanf ("%d", &u);
            printf ("%lld\n", query (1, n, 1, l[u], r[u]));
        }
        else {
            int u, v;
            scanf ("%d%d", &u, &v);
            long long add = v-val[u];
            val[u] = v;
            update (1, n, 1, l[u], r[u], add);
        }
    }
}

void solve () {
    index = 0;
    dfs (0, 0, 0); 
    work (index);
}

int main () {
    //freopen ("in.txt", "r", stdin);
    int t, kase = 0;
    scanf ("%d", &t);
    while (t--) {
        printf ("Case #%d:\n", ++kase);
        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_edge (u, v);
            add_edge (v, u);
        }
        for (int i = 0; i < n; i++) scanf ("%lld", &val[i]);
        solve ();
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值