【BZOJ5210】最大连通子块和(动态DP)(链分治)(线段树)(可删堆)

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/zxyoi_dreamer/article/details/102712068

传送门


链分治维护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;
}

猜你喜欢

转载自blog.csdn.net/zxyoi_dreamer/article/details/102712068