版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
传送门
链分治维护DDP的套路题。
直接维护链外最大值和最大子段和即可。
需要用可删堆,当然multiset也行。
代码:
#include<bits/stdc++.h>
#define ll long long
#define re register
#define cs const
namespace IO{
static cs int Rlen=1<<22|1;
static char buf[Rlen],*p1,*p2;
inline char gc(){return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;}
inline char peek(){return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1;}
inline char ga(){while(!isalpha(peek()))++p1;return *p1++;}
template<typename T>
inline T get(){
char c;T num;bool f=0;
while(!isdigit(c=gc()))f=c=='-';num=c^48;
while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
return f?-num:num;
}
inline int gi(){return get<int>();}
}
using namespace IO;
using std::cerr;
using std::cout;
cs int N=2e5+7;
int n,m;
int el[N],nxt[N<<1|1],to[N<<1|1],ec;
inline void adde(int u,int v){
nxt[++ec]=el[u],el[u]=ec,to[ec]=v;
nxt[++ec]=el[v],el[v]=ec,to[ec]=u;
}
struct heap{
std::priority_queue<ll> a,b;
inline void push(ll v){a.push(v);}
inline void del(ll v){b.push(v);}
inline ll top(){
while(!b.empty()&&a.top()==b.top())a.pop(),b.pop();
return a.top();
}
}s[N];
int fa[N],top[N],bot[N],siz[N],son[N];
int in[N],nd[N],dfn,vl[N];ll f[N],w[N],mx[N];
void dfs1(int u,int p){
for(int re e=el[u],v=to[e];e;v=to[e=nxt[e]])
if(v!=p){
fa[v]=u,dfs1(v,u),siz[u]+=siz[v];
if(siz[v]>siz[son[u]])son[u]=v;
}++siz[u];
}
void dfs2(int u,int tp){
top[u]=tp,in[u]=++dfn,nd[dfn]=u;w[u]=vl[u];
if(son[u]){
dfs2(son[u],tp),f[u]=f[son[u]];
mx[u]=mx[son[u]],bot[u]=bot[son[u]];
}else bot[u]=u;
for(int re e=el[u],v=to[e];e;v=to[e=nxt[e]])
if(v!=fa[u]&&v!=son[u]){
dfs2(v,v);w[u]+=f[v],s[u].push(mx[v]);
}
f[u]=std::max(f[u]+w[u],0ll);
mx[u]=std::max(mx[u],std::max(f[u],s[u].top()));
}
struct node{
ll sum,lmx,rmx,ans;
friend node operator+(cs node &a,cs node &b){
return (node){
a.sum+b.sum,
std::max(a.lmx,a.sum+b.lmx),
std::max(b.rmx,b.sum+a.rmx),
std::max(std::max(a.ans,b.ans),a.rmx+b.lmx)
};
}
}t[N<<2|1];
#define lc u<<1
#define rc u<<1|1
inline void init(int u,int v){
t[u].sum=w[v];t[u].ans=std::max(w[v],s[v].top());
t[u].lmx=t[u].rmx=std::max(w[v],0ll);
}
inline void build(int u,int l,int r){
if(l==r)return init(u,nd[l]);int mid=l+r>>1;
build(lc,l,mid);build(rc,mid+1,r);t[u]=t[lc]+t[rc];
}
inline void ins(int u,int l,int r,int p){
if(l==r)return init(u,nd[l]);int mid=l+r>>1;
(p<=mid)?ins(lc,l,mid,p):ins(rc,mid+1,r,p);t[u]=t[lc]+t[rc];
}
inline node query(int u,int l,int r,int ql,int qr){
if(ql<=l&&r<=qr)return t[u];int mid=l+r>>1;
if(qr<=mid)return query(lc,l,mid,ql,qr);
if(mid<ql)return query(rc,mid+1,r,ql,qr);
return query(lc,l,mid,ql,qr)+query(rc,mid+1,r,ql,qr);
}
#undef lc
#undef rc
inline void Modify(){
int u=gi(),v=gi();
bool flag=false;
node a,b;a.lmx=w[u],b.lmx=w[u]-vl[u]+v;vl[u]=v;
while(u){
w[u]+=b.lmx-a.lmx;
if(flag)s[u].del(a.ans),s[u].push(b.ans);
a=query(1,1,n,in[top[u]],in[bot[u]]);
ins(1,1,n,in[u]);
b=query(1,1,n,in[top[u]],in[bot[u]]);
u=fa[top[u]],flag=true;
}
}
inline void Query(){
int u=gi();
std::cout<<query(1,1,n,in[u],in[bot[u]]).ans<<"\n";
}
signed main(){
#ifdef zxyoi
freopen("tree.in","r",stdin);
#endif
n=gi(),m=gi();
for(int re i=1;i<=n;++i)vl[i]=gi(),s[i].push(0);
for(int re i=1;i<n;++i)adde(gi(),gi());
dfs1(1,0),dfs2(1,1);build(1,1,n);
while(m--)switch(ga()){
case 'Q':Query();break;
case 'M':Modify();break;
}
return 0;
}