【DP】【动态DP】BZOJ5210 最大连通子块和

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_34454069/article/details/88763662

分析:

动态DP板子题,
DP定义式为 f ( i , 0 ) , f ( i , 1 ) f(i,0),f(i,1) 分别表示第i为根的子树中的最大值,以i为根的子树的最大答案,以及第i为根的子树中,与i相连的最大联通子树。

转移:
f ( x , 1 ) = max { f ( u , 1 ) + v a l x , 0 } f(x,1)=\max\{\sum f(u,1)+val_x,0\}
f ( x , 0 ) = max { max { f ( u , 0 ) } , f ( x , 1 ) } f(x,0)=\max\{\max\{f(u,0)\},f(x,1)\}
其中u为x的子节点。

然后,套路地分出轻儿子
l f ( x , 1 ) = max { f ( l u , 1 ) + v a l x , 0 } lf(x,1)=\max\{\sum f(lu,1)+val_x,0\}
l f ( x , 0 ) = max { { f ( l u , 0 ) } , l f ( x , 1 ) } lf(x,0)=\max\{\{f(lu,0)\},lf(x,1)\}
第二个取max的显然需要set来维护了

然后是重链
f ( i , 1 ) = f ( i 1 , 1 ) + l f ( i , 1 ) f(i,1)=\sum f(i-1,1)+lf(i,1)
f ( i , 0 ) = max { f ( i 1 , 0 ) , l f ( i , 0 ) } f(i,0)=\max\{ f(i-1,0),lf(i,0)\}

很容易得到转移矩阵:
[ 0 , f ( i , 0 ) , f ( i , 1 ) ] [ 0 l f ( i , 0 ) 0 0 l f ( i , 1 ) l f ( i , 1 ) ] [0,f(i,0),f(i,1)]*\begin{bmatrix} 0 &lf(i,0) & 0\\ -∞ & 0 & -∞ \\ -∞ & lf(i,1) & lf(i,1)\end{bmatrix}

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<set>
#include<vector>
#define SF scanf
#define PF printf
#define MAXN 200010
#define INF 10000000000000000ll
using namespace std;
typedef long long ll;
struct Matrix{
	ll a[3][3];
	Matrix operator *(const Matrix &b) const {
		Matrix tmp;
		for(int i=0;i<3;i++)
			for(int j=0;j<3;j++)
				tmp.a[i][j]=-INF;
		for(int k=0;k<3;k++)
			for(int i=0;i<3;i++)
				for(int j=0;j<3;j++)
					tmp.a[i][j]=max(tmp.a[i][j],a[i][k]+b.a[k][j]);
		return tmp;
	}
	ll* operator [](const int &x){
		return a[x];
	}
}mul[MAXN],w[MAXN];
multiset<ll> maxp[MAXN];
ll val[MAXN];
int siz[MAXN],son[MAXN],lsiz[MAXN];
int s[MAXN][2];
struct node{
	int u;
	node *nxt;	
}edge[MAXN*2];
node *head[MAXN],*ncnt=edge;
void add_edge(int u,int v){
	ncnt++;
	ncnt->u=v;
	ncnt->nxt=head[u];
	head[u]=ncnt;
	
	ncnt++;
	ncnt->u=u;
	ncnt->nxt=head[v];
	head[v]=ncnt;	
}
void dfs(int x){
	siz[x]=1;
	for(node *e=head[x];e;e=e->nxt){
		int u=e->u;
		if(siz[u])
			continue;
		dfs(u);
		siz[x]+=siz[u];
		if(siz[u]>siz[son[x]])
			son[x]=u;
	}
}
void update(int x){
	if(s[x][0]||son[x]==0)
		mul[x]=mul[s[x][0]]*w[x];
	else
		mul[x]=w[x];
	if(s[x][1])
		mul[x]=mul[x]*mul[s[x][1]];
}
int fa[MAXN];
void setchild(int u,int v){
	w[u][2][1]+=mul[v][0][2];
	w[u][2][2]=w[u][2][1];
	maxp[u].insert(mul[v][0][1]);
	w[u][0][1]=*maxp[u].rbegin();
	w[u][0][1]=max(w[u][0][1],w[u][2][1]);
	fa[v]=u;	
}
bool used[MAXN];
int st[MAXN],tp;
int build(int l,int r){
	if(l>r)
		return 0;
	int tots=0,pres=0;
	for(int i=l;i<=r;i++)
		tots+=lsiz[i];
	for(int i=l;i<=r;i++){
		pres+=lsiz[i];
		if(pres*2>=tots){
			int x=st[i];
			s[x][0]=build(l,i-1);
			s[x][1]=build(i+1,r);
			if(s[x][0])
				fa[s[x][0]]=x;
			if(s[x][1])
				fa[s[x][1]]=x;
			update(x);
			return x;
		}
	}
}
int build_tree(int x){
	for(int i=x;i;i=son[i]){
		used[i]=1;
		lsiz[i]=siz[i]-siz[son[i]];
	}
	for(int i=x;i;i=son[i])
		for(node *e=head[i];e;e=e->nxt){
			int u=e->u;
			if(used[u])
				continue;
			int rs=build_tree(u);	
			setchild(i,rs);
		}
	tp=0;
	for(int i=x;i;i=son[i])
		st[++tp]=i;
	reverse(st+1,st+1+tp);
	return build(1,tp);
}
void change(int x,ll Val){
	w[x][2][1]+=Val-val[x];
	w[x][2][2]=w[x][2][1];
	if(maxp[x].size())
		w[x][0][1]=*maxp[x].rbegin();
	else
		w[x][0][1]=0;
	w[x][0][1]=max(w[x][0][1],w[x][2][1]);
	val[x]=Val;
	int u,v;
	for(int i=x;i;i=fa[i]){
		if(fa[i]&&s[fa[i]][0]!=i&&s[fa[i]][1]!=i){
			v=i;
			u=fa[i];
			maxp[u].erase(maxp[u].find(mul[v][0][1]));
			w[u][2][1]-=mul[v][0][2];
			
			update(i);
			
			maxp[u].insert(mul[v][0][1]);
			w[u][0][1]=*maxp[u].rbegin();
			w[u][2][1]+=mul[v][0][2];
			w[u][2][2]=w[u][2][1];
			w[u][0][1]=max(w[u][0][1],w[u][2][1]);
		}
		else 
			update(i);
	}
}
ll Query(int x){
	Matrix tmp;
	for(int i=0;i<3;i++)
		for(int j=0;j<3;j++)
			tmp[i][j]=0;
	if(son[x]==0)
		return max(0ll,val[x]);
	if(s[x][0])
		tmp=mul[s[x][0]]*w[x];
	else
		tmp=w[x];
	for(int i=x;fa[i]&&(s[fa[i]][0]==i||s[fa[i]][1]==i);i=fa[i]){
		int u=fa[i];
		if(s[u][1]==i){
			if(s[u][0]||son[u]==0)
				tmp=mul[s[u][0]]*w[u]*tmp;
			else
				tmp=w[u]*tmp;
		}
	}
	return tmp[0][1];
}
int n,m,u,v;
char opt[4];
int main(){
	SF("%d%d",&n,&m);
	for(int i=1;i<=n;i++){
		SF("%lld",&val[i]);
		w[i][2][1]=w[i][2][2]=w[i][0][1]=val[i];
		w[i][1][0]=w[i][1][2]=w[i][2][0]=-INF;
	}
	for(int i=1;i<n;i++){
		SF("%d%d",&u,&v);
		add_edge(u,v);
	}
	dfs(1);
	int rt=build_tree(1);
	for(int i=1;i<=m;i++){
		SF("%s",opt);
		if(opt[0]=='Q'){
			SF("%d",&u);
			PF("%lld\n",Query(u));
		}
		else{
			SF("%d%d",&u,&v);
			change(u,v);
		}
	}
}

猜你喜欢

转载自blog.csdn.net/qq_34454069/article/details/88763662
今日推荐