hdu 5692 Snacks(dfs序+线段树)

博客主要探讨了如何使用DFS序结合线段树来解决HDU 5692 'Snacks'问题,通过代码展示了解题思路和方法。

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

Snacks

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


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
 

Source
思路:做的第一道dfs序,甚是觉得这个东西好巧妙。  把树的问题转换成区间上的问题。我们用dfs序可以求出一个点进行先序遍历进入的时间和进行后序遍历进入的时间,那么在这两个时间之间的点既是该点的孩子节点(可以理解为在先序时间之前的点还未经过该点,在上面。而在后序时间之后的点已经出了该树),那么我们得到In[i]和out[i]数组时候,在进行dfs序的同时我们可以得到一个从0节点出发得到的距离数组(因为是树,所以一定只有一条)。然后我们维护一个区间最大值(从0号点出发到这个区间中的某一点所能得到的最大价值)。那么每次把x改为y就是区间更新in[x]~out[x],增加值y-a[x],然后更新a[x]=y即可。每次查询其实求得就是in[x]~out[x]这个区间的最大值,因为只有这个区间里面的点会经过x点

代码:

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

using namespace std;
#define N 100005
#define INF 1e18
int cnt,head[N];
int num;
int in[N],out[N];
int id[N];
long long lazy[4*N],a[N],dis[N];
struct Edge
{
    int v,next;
} edge[4*N];
long long tree[4*N];
void init()
{
    num=0;
    cnt=0;
    memset(head,-1,sizeof(head));
}
void addedge(int u,int v)
{
    edge[cnt].v=v,edge[cnt].next=head[u];
    head[u]=cnt++;
}
void dfs(int u,int last)
{
    in[u]=++num;
    id[num]=u;
    for(int i=head[u]; i!=-1; i=edge[i].next)
    {
        int v=edge[i].v;
        if(v!=last)
        {
            dis[v]=dis[u]+a[v];
            dfs(v,u);
        }
    }
    out[u]=num;
}
void pushup(int root)
{
    tree[root]=max(tree[root<<1],tree[root<<1|1]);
}
void pushdown(int root)
{
    if(lazy[root])
    {
        tree[root<<1]+=lazy[root];
        tree[root<<1|1]+=lazy[root];
        lazy[root<<1]+=lazy[root];
        lazy[root<<1|1]+=lazy[root];
        lazy[root]=0;
    }
}
void build(int l,int r,int root)
{
    lazy[root]=0;
    if(l==r)
    {
        tree[root]=dis[id[l]];
        return;
    }
    int mid=(l+r)>>1;
    build(l,mid,root<<1);
    build(mid+1,r,root<<1|1);
    pushup(root);
}
void Update(int ql,int qr,int v,int l,int r,int root)
{
    if(l>=ql&&r<=qr)
    {
        lazy[root]+=v;
        tree[root]+=v;
        return;
    }
    pushdown(root);
    int mid=(l+r)>>1;
    if(ql<=mid) Update(ql,qr,v,l,mid,root<<1);
    if(qr>mid) Update(ql,qr,v,mid+1,r,root<<1|1);
    pushup(root);
}
long long Query(int ql,int qr,int l,int r,int root)
{
    if(l>=ql&&r<=qr)
        return tree[root];
    pushdown(root);
    int mid=(l+r)>>1;
    long long ans=-INF;
    if(ql<=mid) ans=max(ans,Query(ql,qr,l,mid,root<<1));
    if(qr>mid) ans=max(ans,Query(ql,qr,mid+1,r,root<<1|1));
    return ans;
}
int main()
{
    int T;
    int n,m,u,v;
    int t,x;
    long long y;
    scanf("%d",&T);
    for(int Tcase=1; Tcase<=T; Tcase++)
    {
        init();
        scanf("%d %d",&n,&m);
        for(int i=0; i<n-1; i++)
        {
            scanf("%d %d",&u,&v);
            addedge(u,v);
            addedge(v,u);
        }
        for(int i=0; i<n; i++)
            scanf("%lld",&a[i]);
        dis[0]=a[0];
        dfs(0,-1);
        build(1,n,1);
        printf("Case #%d:\n",Tcase);
        while(m--)
        {
            scanf("%d",&t);
            if(t==0)
            {
                scanf("%d %lld",&x,&y);
                Update(in[x],out[x],y-a[x],1,n,1);
                a[x]=y;
            }
            else
            {
                scanf("%d",&x);
                printf("%lld\n",Query(in[x],out[x],1,n,1));
            }
        }
    }
    return 0;
}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值