分析:一棵以1为根的有根树,然后每个点维护从根到当前节点的路径和,当修改一个点时
只会影响的子树的和,最优值也是子树最大的值
#include <cstdio> #include <iostream> #include <algorithm> #include <cstring> using namespace std; typedef long long LL; const int N=1e5+5; const LL INF=1ll*1e11; struct Edge{ int v,next; }edge[N<<1]; int head[N],tot; void add(int u,int v){ edge[tot].v=v; edge[tot].next=head[u]; head[u]=tot++; } int s[N],t[N],clk,match[N],n,m,a[N]; LL sum[N],c[N<<2],lz[N<<2]; void dfs(int u,int f){ s[u]=++clk;match[s[u]]=u; sum[u]+=sum[f]; for(int i=head[u];~i;i=edge[i].next){ int v=edge[i].v; if(v==f)continue; dfs(v,u); } t[u]=clk; } void up(int rt){ c[rt]=max(c[rt<<1],c[rt<<1|1]); } void down(int rt){ if(lz[rt]){ c[rt<<1]+=lz[rt]; c[rt<<1|1]+=lz[rt]; lz[rt<<1]+=lz[rt]; lz[rt<<1|1]+=lz[rt]; lz[rt]=0; } } void build(int rt,int l,int r){ lz[rt]=0; if(l==r){c[rt]=sum[match[l]];return;} int m=(l+r)>>1; build(rt<<1,l,m); build(rt<<1|1,m+1,r); up(rt); } int tmp; void modify(int rt,int l,int r,int x,int y){ if(x<=l&&r<=y){ lz[rt]+=1ll*tmp; c[rt]+=1ll*tmp; return; } int m=(l+r)>>1; down(rt); if(x<=m)modify(rt<<1,l,m,x,y); if(y>m)modify(rt<<1|1,m+1,r,x,y); up(rt); } LL ask(int rt,int l,int r,int x,int y){ if(x<=l&&r<=y)return c[rt]; LL ans=-INF; int m=(l+r)>>1; down(rt); if(x<=m)ans=max(ans,ask(rt<<1,l,m,x,y)); if(y>m)ans=max(ans,ask(rt<<1|1,m+1,r,x,y)); return ans; } int main() { int T,cas=0; scanf("%d",&T); while(T--){ printf("Case #%d: ",++cas); scanf("%d%d",&n,&m); for(int i=1;i<=n;++i)head[i]=-1; clk=tot=0; for(int i=1;i<n;++i){ int u,v; scanf("%d%d",&u,&v); ++u,++v; add(u,v),add(v,u); } for(int i=1;i<=n;++i) scanf("%I64d",&sum[i]),a[i]=(int)sum[i]; dfs(1,0); build(1,1,n); for(int i=0;i<m;++i){ int op,x,y; scanf("%d%d",&op,&x); ++x; if(!op){ scanf("%d",&y); tmp=y-a[x]; a[x]=y; if(tmp)modify(1,1,n,s[x],t[x]); } else{ printf("%I64d ",ask(1,1,n,s[x],t[x])); } } } return 0; }