HDU5692:DFS序+线段树

HDU5692:Snacks

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

Problem Description

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

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

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

Input

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

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

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

接下来一行由n个数组成,表示从编号为0到编号为n−1的零食机的初始价值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

Source

2016"百度之星" - 初赛(Astar Round2A)

Recommend

wange2014   |   We have carefully selected several similar problems for you:  6460 6459 6458 6457 6456

题解

DFS序一遍,再用线段树维护前缀和。求经过x的最大,即求线段树[id[x],id[x]+sz[x]-1]区间的最大值,id[x]为xDFS序后的新编号,sz[x]为子树(包括本身)的大小。把x编号的值改为y,即区间[id[x],id[x]+sz[x]-1]同时加上该变量y-cost[x]。线段树用lazy标志。

#pragma comment(linker, "/STACK:1024000000,1024000000") 
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
using namespace std;
typedef long long ll;
int const N = 100000 + 10;
ll const inf = 1e18;  //不能用int const inf = 0x7f7f7f7f;
ll n,m,T,tot;
ll first[N],ne[N<<2],to[N<<2],sz[N],id[N];
ll w[N],wt[N];
struct Node
{
    ll l,r;
    ll sum,lazy;
    void updata(ll val){
        sum += val;  //区间更新,求区间最大值;
        lazy += val;
    }
}node[N<<2];
void add(ll x,ll y){
    ne[++tot] = first[x];
    to[tot] = y;
    first[x] = tot;
}
void dfs(ll u,ll f){
    id[u] = ++tot;
    if(f == -1)    wt[tot] = w[u];
    wt[tot] = wt[id[f]] + w[u];
    sz[u] = 1;
    for(ll i=first[u];i;i=ne[i]){
        ll v = to[i];
        if(v == f)    continue;
        dfs(v,u);
        sz[u] += sz[v];
    }
}
void push_down(ll id){
    ll lazy = node[id].lazy;
    if(lazy){
        node[id<<1].updata(lazy);
        node[id<<1|1].updata(lazy);
        node[id].lazy = 0;
    }
}
void push_up(ll id){
    node[id].sum = max(node[id<<1].sum,node[id<<1|1].sum);
}
void build(ll id,ll l,ll r){
    node[id].l = l,    node[id].r = r;
    node[id].lazy = node[id].sum = 0;
    if(l == r){
        node[id].sum = wt[l];
    }else{
        ll mid = (l + r) >> 1;
        build(id<<1,l,mid);
        build(id<<1|1,mid+1,r);
        push_up(id);
    }
}
void updata(ll id,ll L,ll R,ll k){
    ll l = node[id].l,    r = node[id].r;
    if(L <=l && r <= R){
        node[id].updata(k);  
    }else{
        ll mid = (l + r) >> 1;
        push_down(id);
        if(L <= mid)    updata(id<<1,L,R,k);
        if(mid < R)        updata(id<<1|1,L,R,k);
        push_up(id);
    }
}
ll query(ll id,ll L,ll R){
    ll l = node[id].l,    r = node[id].r;
    if(L <= l && r <= R){
        return node[id].sum;
    }else{
        ll mid = (l + r) >> 1;
        push_down(id);
        ll res = -inf;  //注意不能初始化为0,题目给出的v绝对值小于100000.debug了半天。。。
        if(L <= mid)    res = max(query(id<<1,L,R),res);
        if(mid < R)        res = max(query(id<<1|1,L,R),res);
        //push_up(id);
        return res;
    }
}
void Init(){
    memset(first,0,sizeof(first));
    tot = 0;
    scanf("%lld%lld",&n,&m);
    for(ll i=1;i<=n-1;i++){
        ll x,y;    scanf("%lld%lld",&x,&y);
        add(x,y);    add(y,x);
    }
    for(ll i=0;i<=n-1;i++)    scanf("%lld",&w[i]);
    tot = 0;
    dfs(0,-1);
    build(1,1,n);
}
void solve(ll caser){
    printf("Case #%lld:\n",caser);
    ll k,x,y;
    for(ll i=1;i<=m;i++){
        scanf("%lld",&k);
        if(k == 0){
            scanf("%lld%lld",&x,&y);
            ll change = y - w[x];
            updata(1,id[x],id[x]+sz[x]-1,change);
            w[x] = y;
        }else{
            scanf("%lld",&x);
            printf("%lld\n",query(1,id[x],id[x]+sz[x]-1));

        }
    }
}
int main(){
    scanf("%lld",&T);
    for(ll caser=1;caser<=T;caser++){
        Init();
        solve(caser);
    }
    return 0;
}

 

posted @ 2019-02-06 13:56  月光下の魔术师  阅读(11)  评论(0)    收藏  举报