HDU 5692 Snacks(DFS序+线段树)

Problem Description

百度科技园内有个零食机,零食机之间通过条路相互连通。每个零食机都有一个值,表示为小度熊提供零食的价值。
由于零食被频繁的消耗和补充,零食机的价值会时常发生变化。小度熊只能从编号为0的零食机出发,并且每个零食机至多经过一次。另外,小度熊会对某个零食机的零食有所偏爱,要求路线上必须有那个零食机。
为小度熊规划一个路线,使得路线上的价值总和最大。

 

Input

输入数据第一行是一个整数,表示有组测试数据。
对于每组数据,包含两个整数,表示有个零食机,次操作。
接下来行,每行两个整数和,表示编号为的零食机与编号为的零食机相连。
接下来一行由个数组成,表示从编号为0到编号为的零食机的初始价值。
接下来行,有两种操作:,表示编号为的零食机的价值变为;,表示询问从编号为0的零食机出发,必须经过编号为零食机的路线中,价值总和的最大值。
本题可能栈溢出,辛苦同学们提交语言选择c++,并在代码的第一行加上:
`#pragma comment(linker, "/STACK:1024000000,1024000000") `

 

Output

对于每组数据,首先输出一行”Case #?:”,在问号处应填入当前数据的组数,组数从1开始计算。
对于每次询问,输出从编号为0的零食机出发,必须经过编号为零食机的路线中,价值总和的最大值。

 

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

思路:求经过x点到0点的最长路径 就直接用每个点到0点的距离建一颗线段树 维护最大值就可以 因为还要经过x点 就需要跑一边DFS序 l[x],r[x]就表示x子树的区间范围 x的子树上的点一定经过x 所以只需求l[x]~r[x]的区间最大值就是答案 修改操作就是线段树的区间修改

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <iostream>
#include <algorithm>
#include <vector>
#define ll long long
#define inf 0x3f3f3f3f3f3f

using namespace std;

int L[100005], R[100005],tot;
ll Max[400005],lazy[400005],vv[100005];
int v[100005];
vector <int> Map[100005];

void dfs(int x,int fa,ll value)
{
    L[x]=++tot;
    vv[tot]=value;
    for(int i=0;i<Map[x].size();i++)
    {
        if(Map[x][i]==fa)
        {
            continue;
        }
        dfs(Map[x][i],x,value+v[Map[x][i]]);
    }
    R[x]=tot;
}

void build(int l,int r,int rt)
{
    lazy[rt]=0;
    if(l==r)
    {
        Max[rt]=vv[l];
        return;
    }
    int mid=(l+r)>>1;
    build(l,mid,rt<<1);
    build(mid+1,r,rt<<1|1);
    Max[rt]=max(Max[rt<<1],Max[rt<<1|1]);
}

void update(int l,int r,int L,int R,int x,int rt)
{
    if(L<=l&&R>=r)
    {
        Max[rt]+=x;
        lazy[rt]+=x;
        return;
    }
    int mid=(l+r)>>1;
    if(lazy[rt])
    {
        Max[rt<<1]+=lazy[rt];
        Max[rt<<1|1]+=lazy[rt];
        lazy[rt<<1]+=lazy[rt];
        lazy[rt<<1|1]+=lazy[rt];
        lazy[rt]=0;
    }
    if(L<=mid)
    {
        update(l,mid,L,R,x,rt<<1);
    }
    if(R>mid)
    {
        update(mid+1,r,L,R,x,rt<<1|1);
    }
    Max[rt]=max(Max[rt<<1],Max[rt<<1|1]);
}

ll query(int l,int r,int L,int R,int rt)
{
    if(L<=l&&R>=r)
    {
        return Max[rt];
    }
    int mid=(l+r)>>1;
    if(lazy[rt])
    {
        Max[rt<<1]+=lazy[rt];
        Max[rt<<1|1]+=lazy[rt];
        lazy[rt<<1]+=lazy[rt];
        lazy[rt<<1|1]+=lazy[rt];
        lazy[rt]=0;
    }
    ll ans=-inf;
    if(L<=mid)
    {
        ans=max(ans,query(l,mid,L,R,rt<<1));
    }
    if(R>mid)
    {
        ans=max(ans,query(mid+1,r,L,R,rt<<1|1));
    }
    return ans;
}

signed main()
{
    int T,cas=0;
    scanf("%d",&T);
    while(T--)
    {
        tot=-1;
        int n,m;
        scanf("%d%d",&n,&m);
        for(int i=0;i<n;i++)
        {
            Map[i].clear();
        }
        for(int i=1;i<n;i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            Map[u].push_back(v);
            Map[v].push_back(u);
        }
        for(int i=0;i<n;i++)
        {
            scanf("%d",&v[i]);
        }
        dfs(0,-1,v[0]);
        build(0,n-1,1);
        printf("Case #%d:\n",++cas);
        while(m--)
        {
            int x;
            scanf("%d",&x);
            if (x==0)
            {
                int y,z;
                scanf("%d%d",&y,&z);
                update(0,n-1,L[y],R[y],z-v[y],1);
                v[y]=z;
            }
            else
            {
                int y;
                scanf("%d",&y);
                printf("%lld\n",query(0,n-1,L[y],R[y],1));
            }
        }
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值