Snacks
Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 2165 Accepted Submission(s): 513
Problem 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
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
102
27
2
20
这题是把树化为线性去处理的典型题。
对于本题我们要求的是经过从根并经过点s的路径最大权值,即到达该点和该点子树上每个节点的路径总权值里的最大值。这个可以用前缀和求出到每个点的总权值。并且这之中带有权值修改,一下就令人想到线段树。但线段树维护的是一个区间上的值,那怎么把一颗树化为线性呢?那么此时dfs时间戳就派上用场了。我们需要把一棵树用dfs时间戳将这棵树化为一个线性的区间,区间每个点存的是dfs时间戳里的节点所对应的从0根节点到该节点的路径总权值。此时我们要求解点s的从根并经过点s的路径最大权值,就变成了求解pre[s]~last[s]这个区间里所有权值的最大值,而修改某个点u的权值相当于更新pre[u]~last[u]里的所有权值。于是该题就能用线段树维护求解了。
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<cstdio>
#include<iostream>
#include<cstring>
#define clr(x) memset(x,0,sizeof(x))
#define clr_1(x) memset(x,-1,sizeof(x))
#define LL long long
#define INF (1e18)
using namespace std;
struct edg
{
int next,to;
}edge[<<];
struct seg
{
int l,r;
LL maxn,tag;
}segt[<<];
int head[],dfstm[],pre[],last[],n,m,k,u,v,s,T,cnt;
LL value[],sum[],x;
LL max(LL a, LL b)
{
return a>b?a:b;
}
void addedge(int u,int v)
{
edge[++cnt].to=v;
edge[cnt].next=head[u];
head[u]=cnt;
return ;
}
void dfs(int i,int fa)
{
sum[i]=sum[fa]+value[i];
dfstm[++k]=i;
pre[i]=k;
for(int j=head[i];j!=-;j=edge[j].next)
if(edge[j].to!=fa)
dfs(edge[j].to,i);
last[i]=k;
return ;
}
void init(int i,int l,int r)
{
segt[i]=(seg){l,r,,};
if(l==r)
{
segt[i].maxn=sum[dfstm[l]];
return;
}
int mid=(l+r)>>;
init(i<<,l,mid);
init(i<<|,mid+,r);
segt[i].maxn=max(segt[i<<].maxn,segt[i<<|].maxn);
return ;
}
void pushdown(int i)
{
if(segt[i].tag!=)
{
if(segt[i].l!=segt[i].r)
{
segt[i<<].maxn+=segt[i].tag;
segt[i<<|].maxn+=segt[i].tag;
segt[i<<].tag+=segt[i].tag;
segt[i<<|].tag+=segt[i].tag;
}
segt[i].tag=;
}
return ;
}
void update(int i,int l,int r,LL addval)
{
if(segt[i].l>=l && segt[i].r<=r)
{
segt[i].tag+=addval;
segt[i].maxn+=addval;
return ;
}
pushdown(i);
int mid=(segt[i].l+segt[i].r)>>;
if(mid>=r)
{
update(i<<,l,r,addval);
}
else if(mid<l)
{
update(i<<|,l,r,addval);
}
else
{
update(i<<,l,r,addval);
update(i<<|,l,r,addval);
}
segt[i].maxn=max(segt[i<<].maxn,segt[i<<|].maxn);
return ;
}
LL query(int i,int l,int r)
{
if(segt[i].l>=l && segt[i].r<=r)
{
return segt[i].maxn;
}
pushdown(i);
int mid=(segt[i].l+segt[i].r)>>;
LL ans=-INF;
if(mid>=r)
{
ans=max(ans,query(i<<,l,r));
}
else if(mid<l)
{
ans=max(ans,query(i<<|,l,r));
}
else
{
ans=max(ans,query(i<<,l,r));
ans=max(ans,query(i<<|,l,r));
}
segt[i].maxn=max(segt[i<<].maxn,segt[i<<|].maxn);
return ans;
}
int main()
{
scanf("%d",&T);
for(int kase=;kase<=T;kase++)
{
clr_1(head);
clr(sum);
cnt=;
k=;
printf("Case #%d:\n",kase);
scanf("%d%d",&n,&m);
for(int i=;i<n;i++)
{
scanf("%d%d",&u,&v);
addedge(u,v);
addedge(v,u);
}
for(int i=;i<n;i++)
{
scanf("%lld",&value[i]);
}
dfs(,);
init(,,n);
for(int i=;i<=m;i++)
{
scanf("%d",&k);
if(k)
{
scanf("%d",&u);
printf("%lld\n",query(,pre[u],last[u]));
}
else
{
scanf("%d%lld",&u,&x);
update(,pre[u],last[u],x-value[u]);
value[u]=x;
}
}
}
return ;
}