题目链接: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
*/