题意
一棵
个节点的树,每个点有点权。在线实现
个操作,操作分两种:改变某点的点权,询问以
为节点,必须经过节点
的路径中点权和的最大值。
思路
树上维护的东西一般跟询问有关,这里就按照题意,维护从 出发到某个节点的点权和,而经过 的路径,说明路径的终点一定属于以 为根的子树。那么在 的子树中取最大值即可,由此想到 序,并通过线段树查询区间最大值。而改变某个点的点权,会导致它的子树的值整体同时增加或减少一个同样的值,说明线段树的修改是区间加值的。再维护某个点实时的点权,并把修改点权改成在原来点权的基础上加一个值即可。
代码
#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define FOR(i,x,y) for(int i=(x);i<=(y);i++)
#define DOR(i,x,y) for(int i=(x);i>=(y);i--)
#pragma comment(linker, "/STACK:1024000000,1024000000")
#define N 100003
typedef long long LL;
using namespace std;
LL now[N];
template<const int maxn,const int maxm>struct Linked_list
{
int head[maxn],to[maxm],nxt[maxm],tot;
void clear(){memset(head,-1,sizeof(head));tot=0;}
void add(int u,int v){to[++tot]=v,nxt[tot]=head[u];head[u]=tot;}
#define EOR(i,G,u) for(int i=G.head[u];~i;i=G.nxt[i])
};
struct node
{
int L,R;
LL maxer,tag;
void tag_up(LL val)
{
tag+=val;
maxer+=val;
}
node operator +(const node &_)const{return (node){L,_.R,max(maxer,_.maxer),0};}
};
struct SegmentTree
{
node nd[N<<2];
void build(int k,int L,int R)
{
if(L==R)
{
nd[k].L=nd[k].R=L;
nd[k].maxer=0;
nd[k].tag=0;
return;
}
build(k<<1,L,L+R>>1);
build(k<<1|1,(L+R>>1)+1,R);
nd[k]=nd[k<<1]+nd[k<<1|1];
}
void push_down(int k)
{
if(!nd[k].tag)return;
nd[k<<1].tag_up(nd[k].tag);
nd[k<<1|1].tag_up(nd[k].tag);
nd[k].tag=0;
}
void update(int k,int L,int R,LL val)
{
if(L<=nd[k].L&&nd[k].R<=R)
{
nd[k].tag_up(val);
return;
}
push_down(k);
int mid=nd[k].L+nd[k].R>>1;
if(L<=mid)update(k<<1,L,R,val);
if(mid<R)update(k<<1|1,L,R,val);
nd[k]=nd[k<<1]+nd[k<<1|1];
}
LL query(int k,int L,int R)
{
if(L<=nd[k].L&&nd[k].R<=R)return nd[k].maxer;
push_down(k);
int mid=nd[k].L+nd[k].R>>1;
if(R<=mid)return query(k<<1,L,R);
else if(L>mid)return query(k<<1|1,L,R);
else return max(query(k<<1,L,R),query(k<<1|1,L,R));
}
};
struct Tree
{
Linked_list<N,N<<1>G;
SegmentTree ST;
int L[N],R[N],n,ord;
void reset(int _){G.clear();ST.build(1,1,n=_);ord=0;}
void add(int u,int v){G.add(u,v);G.add(v,u);}
void dfs(int u,int fa)
{
L[u]=++ord;
EOR(i,G,u)
{
int v=G.to[i];
if(v!=fa)dfs(v,u);
}
R[u]=ord;
return;
}
void update(int k,LL val)
{
ST.update(1,L[k],R[k],val-now[k]);
now[k]=val;
}
void addval(int k,LL val){ST.update(1,L[k],R[k],val);}
LL query(int k){return ST.query(1,L[k],R[k]);}
}T;
int main()
{
int Task,n,m;
scanf("%d",&Task);
FOR(Ti,1,Task)
{
scanf("%d%d",&n,&m);
printf("Case #%d:\n",Ti);
T.reset(n);
FOR(i,1,n-1)
{
int u,v;
scanf("%d%d",&u,&v);
T.add(u+1,v+1);
}
T.dfs(1,-1);
FOR(i,1,n)
{
scanf("%lld",&now[i]);
T.addval(i,now[i]);
}
while(m--)
{
int op,x;
LL y;
scanf("%d",&op);
if(op==1)
{
scanf("%d",&x);
printf("%lld\n",T.query(x+1));
}
else if(op==0)
{
scanf("%d%lld",&x,&y);
T.update(x+1,y);
}
}
}
return 0;
}