HDU-5692-Snacks(DFS序+线段树)

42 篇文章 0 订阅

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5692



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

Hint



题解:DFS序+线段

DFS序标号,同时计算每个点到树根的权值和cost[p],

然后线段树维护标号区间最大值,即区间(子树)中权值cost[p]最大点。


//#include <bits/stdc++.h>
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <vector>
#include <algorithm>
using namespace std;
int Scan()
{
    int res=0,ch,flag=0;
    if((ch=getchar())=='-')flag=1;
    else if(ch>='0'&&ch<='9')res=ch-'0';
    while((ch=getchar())>='0'&&ch<='9')res=res*10+ch-'0';
    return flag?-res:res;
}
void Out(int a)
{
    if(a>9)Out(a/10);
    putchar(a%10+'0');
}
#define INF 0x3f3f3f3f
#define LL long long
#define bug cout<<"bug"<<endl
const long long inf = 0x3f3f3f3f3f3f3f3f;
const int MAXN = 1e6+7;
vector<int> tree[MAXN];
int L[MAXN],R[MAXN];
long long cost[MAXN],val[MAXN],max_nod[MAXN],wait[MAXN];
int index;
void DFS(int u,int fa, long long c)
{
    L[u]=++index,cost[index]=c;
    int len=tree[u].size();
    for(int i=0; i<len; ++i)
    {
        int v=tree[u][i];
        if(v==fa)continue;
        DFS(v,u,c+val[v]);
    }
    R[u]=index;
}
void push_data(int poi)
{
    if(wait[poi])
    {
        wait[poi<<1]+=wait[poi];
        wait[poi<<1^1]+=wait[poi];
        max_nod[poi<<1]+=wait[poi];
        max_nod[poi<<1^1]+=wait[poi];
        wait[poi]=0;
    }
}
void build_tree(int l, int r, int poi)
{
    if(l==r){max_nod[poi]=cost[l];return;}
    int mid=(l+r)>>1;
    build_tree(l,mid,poi<<1);
    build_tree(mid+1,r,poi<<1^1);
    max_nod[poi]=max(max_nod[poi<<1],max_nod[poi<<1^1]);
}
void update(int l, int r, int a, int b, int poi, long long c)
{
    if(l<=a && b<=r)
    {
        max_nod[poi]+=c;
        wait[poi]+=c;
        return;
    }
    push_data(poi);
    int mid=(a+b)>>1;
    if(mid>=l)update(l,r,a,mid,poi<<1,c);
    if(mid<r)update(l,r,mid+1,b,poi<<1^1,c);
    max_nod[poi]=max(max_nod[poi<<1],max_nod[poi<<1^1]);
}
long long query(int l, int r, int a, int b, int poi)
{
    long long ans=-inf;
    if(l<=a && b<=r)return max_nod[poi];
    push_data(poi);
    int mid=(a+b)>>1;
    if(mid>=l)ans=max(ans,query(l,r,a,mid,poi<<1));
    if(mid<r)ans=max(ans,query(l,r,mid+1,b,poi<<1^1));
    return ans;
}
int main()
{
    int T,n,m,a,b,c;
    T=Scan();int cas=0;
    while(T--)
    {
        index=0;
        n=Scan();m=Scan();
        memset(wait,0,sizeof(wait));
        memset(max_nod,0,sizeof(max_nod));
        for(int i=0; i<=n; ++i)tree[i].clear();
        for(int i=0; i<n-1; ++i)
        {
            a=Scan();b=Scan();
            ++a,++b;
            tree[a].push_back(b);
            tree[b].push_back(a);
        }
        for(int i=1; i<=n; ++i)
            scanf("%I64d",&val[i]);
        DFS(1,0,val[1]);
        build_tree(1,n,1);
        printf("Case #%d:\n",++cas);
        while(m--)
        {
            a=Scan();b=Scan();++b;
            if(a)printf("%I64d\n",query(L[b],R[b],1,n,1));
            else
            {
                c=Scan();
                update(L[b],R[b],1,n,1,c-val[b]);
                val[b]=c;
            }
        }
    }
    return 0;
}

/*
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
*/


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值