【图论+线段树】[2016"百度之星" - 初赛(Astar Round2A)]Snacks
题目
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
#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
分析
根据题意,就是动态维护以当前点为根的子树内的点的深度的最大值,求出dfs序用线段树维护即可。
代码
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
#define MAXN 100000
int n,st[MAXN+10],ed[MAXN+10],dcnt,rdfn[MAXN+10],wt[MAXN+10],m,T;
long long dep[MAXN+10];
template<class T>
void Read(T &x){
char c;
bool f=0;
while(c=getchar(),c!=EOF){
if(c=='-')
f=1;
if(c>='0'&&c<='9'){
x=c-'0';
while(c=getchar(),c>='0'&&c<='9')
x=x*10+c-'0';
ungetc(c,stdin);
if(f)
x=-x;
return;
}
}
}
struct node{
int v;
node *next;
}*adj[MAXN+10],edge[MAXN*2+10],*ecnt=edge;
inline void addedge(int u,int v){
node *p=++ecnt;
p->v=v;
p->next=adj[u];
adj[u]=p;
}
namespace SegmentTree{
struct node{
long long mx,tag;
}tree[MAXN*4+10];
inline void update(int i){
tree[i].mx=max(tree[i<<1].mx,tree[(i<<1)|1].mx);
}
inline void push_down(int i){
if(tree[i].tag){
tree[i<<1].mx+=tree[i].tag,tree[i<<1].tag+=tree[i].tag;
tree[(i<<1)|1].mx+=tree[i].tag,tree[(i<<1)|1].tag+=tree[i].tag;
tree[i].tag=0;
}
}
void insert(int i,int l,int r,int ll,int rr,int d){
if(ll<=l&&r<=rr){
tree[i].tag+=d;
tree[i].mx+=d;
return;
}
if(ll>r||rr<l)
return;
push_down(i);
int mid=(l+r)>>1;
insert(i<<1,l,mid,ll,rr,d);
insert((i<<1)|1,mid+1,r,ll,rr,d);
update(i);
}
long long get_mx(int i,int l,int r,int ll,int rr){
if(ll<=l&&r<=rr)
return tree[i].mx;
if(ll>r||rr<l)
return 0x8000000000000000ll;
push_down(i);
int mid=(l+r)>>1;
return max(get_mx(i<<1,l,mid,ll,rr),get_mx((i<<1)|1,mid+1,r,ll,rr));
}
void build(int i,int l,int r){
tree[i].tag=0;
if(l==r){
tree[i].mx=dep[rdfn[l]];
return;
}
int mid=(l+r)>>1;
build(i<<1,l,mid);
build((i<<1)|1,mid+1,r);
update(i);
}
}
void dfs(int u,int fa){
st[u]=++dcnt;
dep[u]=dep[fa]+wt[u];
rdfn[dcnt]=u;
for(node *p=adj[u];p;p=p->next)
if(p->v!=fa)
dfs(p->v,u);
ed[u]=dcnt;
}
using namespace SegmentTree;
void read(){
Read(n),Read(m);
int i,u,v;
for(i=1;i<n;i++){
Read(u),Read(v);
addedge(u,v);
addedge(v,u);
}
for(i=0;i<n;i++)
Read(wt[i]);
}
void solve(){
dep[0]=0;
dfs(0,0);
build(1,1,n);
int p,x,y;
while(m--){
Read(p);
if(!p){
Read(x),Read(y);
insert(1,1,n,st[x],ed[x],y-wt[x]);
wt[x]=y;
}
else{
Read(x);
printf("%I64d\n",get_mx(1,1,n,st[x],ed[x]));
}
}
}
int main()
{
Read(T);
int cnt=0;
while(T--){
dcnt=0;
printf("Case #%d:\n",++cnt);
memset(adj,0,sizeof adj);
ecnt=edge;
read();
solve();
}
}