HDU 5692 Snacks(线段树)

思路:题目要求必须从0号结点经过x号结点,那么其实就是求x号结点的子树到0号结点的最大距离,那么可以先DFS一遍把DFS序弄出来,顺便预处理每一个结点到0号结点的距离,然后建线段树,维护结点到0号结点的距离就可以了


#pragma comment(linker, "/STACK:1024000000,1024000000") `
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define lson i<<1,l,mid
#define rson i<<1|1,mid+1,r
const int maxn = 100000+7;
#define inf 1LL<<58
LL dis[maxn],a[maxn];
LL sum[maxn<<2],lazy[maxn<<2];
vector<int>e[maxn];
int n,m,in[maxn],out[maxn],vis[maxn],tot;
void push_up(int i)
{
    sum[i]=max(sum[i<<1],sum[i<<1|1]);
}
void push_down(int i)
{
	if(lazy[i])
	{
		lazy[i<<1]+=lazy[i];
		lazy[i<<1|1]+=lazy[i];
		sum[i<<1]+=lazy[i];
		sum[i<<1|1]+=lazy[i];
		lazy[i]=0;
	}
}
void build(int i,int l,int r)
{
	lazy[i]=0;
	if(l==r)
	{
		sum[i]=dis[vis[l]];
		return;
	}
	int mid = (l+r)>>1;
	build(lson);
	build(rson);
	push_up(i);
}
void update(int ql,int qr,int v,int i,int l,int r)
{
    if(ql<=l&&qr>=r)
	{
		lazy[i]+=v;
		sum[i]+=v;
	    return;
	}
	push_down(i);
	int mid = (l+r)>>1;
	if(ql<=mid)
		update(ql,qr,v,lson);
	if(qr>mid)
		update(ql,qr,v,rson);
	push_up(i);
}
LL query(int ql,int qr,int i,int l,int r)
{
	if(ql<=l&&qr>=r)
		return sum[i];
	push_down(i);
	int mid = (l+r)>>1;
	LL ans = -inf;
    if(ql<=mid)
       ans = max(ans,query(ql,qr,lson));
	if(qr>mid)
		ans = max(ans,query(ql,qr,rson));
	return ans;
}
void dfs(int u,int fa)
{
    in[u]=++tot;
	vis[tot]=u;
	for(int i = 0;i<e[u].size();i++)
	{
		int v = e[u][i];
		if(v==fa)continue;
		dis[v] = dis[u]+a[v];
		dfs(v,u);
	//	dis[v]=dis[u]+a[v];
	}
	out[u]=tot;
}  
int main()
{
    int T,cas=1;
	scanf("%d",&T);
	while(T--)
	{
		printf("Case #%d:\n",cas++);
        scanf("%d%d",&n,&m);
		for(int i = 0;i<=n;i++)
			e[i].clear();
		tot=0;
		for(int i = 0;i<n-1;i++)
		{
			int u,v;
			scanf("%d%d",&u,&v);
			u++,v++;
			e[u].push_back(v);
			e[v].push_back(u);
		}
		for(int i =1;i<=n;i++)
			scanf("%lld",&a[i]);
		dis[1]=a[1];
		dfs(1,-1);
		build(1,1,tot);
		for(int i = 1;i<=m;i++)
		{
			int op;
			scanf("%d",&op);
			if(op==0)
			{
                int u,v;
				scanf("%d%d",&u,&v);
				u++;
				update(in[u],out[u],v-a[u],1,1,tot);
				a[u]=v;
			}
			else
			{
				int u;
				scanf("%d",&u);
				u++;
                printf("%lld\n",query(in[u],out[u],1,1,tot));
			}
		}
	}
}

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


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值