传送门

题意:支持单点修改,维护子树里的最大连通子块和。


思路:

扯皮:

bzojbzojbzoj卡常差评。

网上的题解大多用了跟什么最大子段和一样的转移方法。

但是我们实际上是可以用矩阵转移的传统ddpddpddp写法来做这道题的。

由于我推出来矩阵是3∗33*33∗3的因此常数巨大gggggg了,因此蒟蒻博主只能提供思路和一份TLETLETLE的代码。

正题:

一道考虑链分治+dpdpdp套路题。

同样先考虑静态的版本。

显然可以fi,0/1f_{i,0/1}fi,0/1​表示以iii为根的子树,iii在/不在最大子块里是的最大子块和是多少。

然后显然有如下两个转移式:

fp,0=maxv∈son{fv,0,fv,1}f_{p,0}=max_{v\in son}\{f_{v,0},f_{v,1}\}fp,0​=maxv∈son​{fv,0​,fv,1​}

fp,1=vali+∑v∈sonmax{fv,1,0}f_{p,1}=val_i+\sum_{v\in son}max\{f_{v,1},0\}fp,1​=vali​+∑v∈son​max{fv,1​,0}。

现在考虑链分治,我们记一个gi,0/1g_{i,0/1}gi,0/1​表示跟以iii为根的子树去掉iii的重儿子所在子树之后,iii在/不在最大子块里时的最大子块和是多少。

考虑推ggg:

gp,0=maxv∈son,v̸=hson{fv,0,fv,1}g_{p,0}=max_{v\in son,v\not=hson}\{f_{v,0},f_{v,1}\}gp,0​=maxv∈son,v̸​=hson​{fv,0​,fv,1​}

gp,1=fi,1=vali+∑v∈son,v̸=hsonmax{0,fv,1}g_{p,1}=f_{i,1}=val_i+\sum_{v\in son,v\not=hson}max\{0,f_{v,1}\}gp,1​=fi,1​=vali​+∑v∈son,v̸​=hson​max{0,fv,1​}

于是就可以用fhsonf_{hson}fhson​和gpg_pgp​来更新fpf_pfp​:

fp,0=max{gp,0,fhson,0,fhson,1}f_{p,0}=max\{g_{p,0},f_{hson,0},f_{hson,1}\}fp,0​=max{gp,0​,fhson,0​,fhson,1​}

fp,1=gp,1+valp+max{0,fhson,1}f_{p,1}=g_{p,1}+val_p+max\{0,f_{hson,1}\}fp,1​=gp,1​+valp​+max{0,fhson,1​}

那么这个可以用矩阵的形式来表示:

(0fp,0fp,1)=(0−∞−∞gp,000gp,1+valp−∞gp,1+valp)∗(0fhson,0fhson,1)
\left (
\begin{matrix}
0\\
f_{p,0}\\
f_{p,1}\\
\end{matrix}
\right)=
\left (
\begin{matrix}
0&-\infin&-\infin\\
g_{p,0}&0&0\\
g_{p,1}+val_p&-\infin&g_{p,1}+val_p\\
\end{matrix}
\right)*
\left(
\begin{matrix}
0\\
f_{hson,0}\\
f_{hson,1}\\
\end{matrix}
\right)
⎝⎛​0fp,0​fp,1​​⎠⎞​=⎝⎛​0gp,0​gp,1​+valp​​−∞0−∞​−∞0gp,1​+valp​​⎠⎞​∗⎝⎛​0fhson,0​fhson,1​​⎠⎞​

于是对于每条重链开一棵线段树来维护左边3∗33*33∗3矩阵的转移即可。

代码(被卡常):

#include<bits/stdc++.h>
#define ri register int
#define fi first
#define se second
using namespace std;
typedef long long ll;
typedef pair<ll,ll> pii;
const int N=2e5+5;
const ll inf=1e15;
inline int read(){
	int ans=0,w=1;
	char ch=getchar();
	while(!isdigit(ch)){if(ch=='-')w=-1;ch=getchar();}
	while(isdigit(ch))ans=(((ans<<2)+ans)<<1)+(ch^48),ch=getchar();
	return ~w?ans:-ans;
}
struct deletable_queue{
	priority_queue<ll>a,b;
	inline void push(const ll&x){a.push(x);}
	inline void del(const ll&x){b.push(x);}
	inline ll top(){while(b.size()&&a.top()==b.top())a.pop(),b.pop();return a.top();}
}S[N];
int fa[N],top[N],num[N],hson[N],siz[N],dep[N],pred[N],vl[N],bot[N],n,m,tot=0;
ll f[N][2],g[N][2];
vector<int>e[N];
inline ll M(const ll&a,const ll&b){return (a!=-inf)&&(b!=-inf)?a+b:-inf;}
void dfs1(int p){
	siz[p]=1;
	for(ri i=0,v;i<e[p].size();++i){
		if((v=e[p][i])==fa[p])continue;
		fa[v]=p,dep[v]=dep[p]+1,dfs1(v),siz[p]+=siz[v];
		if(siz[v]>siz[hson[p]])hson[p]=v;
	}
}
void dfs2(int p,int tp){
	top[p]=tp,pred[num[p]=++tot]=p,bot[tp]=p;
	g[p][0]=g[p][1]=f[p][0]=0,f[p][1]=vl[p];
	if(!hson[p])return;
	dfs2(hson[p],tp);
	for(ri i=0,v;i<e[p].size();++i){
		if((v=e[p][i])==fa[p]||v==hson[p])continue;
		dfs2(v,v);
		S[p].push(max(f[v][0],f[v][1]));
		g[p][1]+=max(0ll,f[v][1]);
	}
	g[p][0]=S[p].top();
	f[p][0]=max(g[p][0],max(f[hson[p]][0],f[hson[p]][1]));
	f[p][1]=vl[p]+g[p][1]+max(0ll,f[hson[p]][1]);
}
struct Mat{
	ll a[3][3];
	inline ll*operator[](const int&k){return a[k];}
	inline void clear(){for(ri i=0;i<3;++i)for(ri j=0;j<3;++j)a[i][j]=-inf;}
	friend inline Mat operator*(Mat A,Mat B){
		Mat ret;
		ret.clear();
		for(ri i=0;i<3;++i)for(ri k=0;k<3;++k)for(ri j=0;j<3;++j)ret[i][j]=max(ret[i][j],M(A[i][k],B[k][j]));
		return ret;
	}
};
namespace SGT{
	#define lc (p<<1)
	#define rc (p<<1|1)
	#define mid (T[p].l+T[p].r>>1)
	struct Node{
		int l,r,v;
		ll f[2],g[2];
		Mat trans;
		inline void init(){
			trans[0][0]=0,trans[0][1]=-inf,trans[0][2]=-inf;
			trans[1][0]=g[0],trans[1][1]=0,trans[1][2]=0;
			trans[2][0]=g[1]+v,trans[2][1]=-inf,trans[2][2]=g[1]+v;
		}
		inline pii val(){return pii(f[0],f[1]);}
	}T[N<<2];
	inline void Set(int p){
		int k=pred[T[p].l];
		T[p].f[0]=f[k][0],T[p].f[1]=f[k][1];
		T[p].g[0]=g[k][0],T[p].g[1]=g[k][1];
		T[p].v=vl[k],T[p].init();
	}
	inline void pushup(int p){T[p].trans=T[lc].trans*T[rc].trans;}
	inline void build(int p,int l,int r){
		T[p].l=l,T[p].r=r;
		if(l==r)return Set(p);
		build(lc,l,mid),build(rc,mid+1,r),pushup(p);
	}
	inline void update(int p,int k){
		if(T[p].l==T[p].r)return Set(p);
		update(k<=mid?lc:rc,k),pushup(p);
	}
	inline Mat query(int p,int ql,int qr){
		if(ql<=T[p].l&&T[p].r<=qr)return T[p].trans;
		if(qr<=mid)return query(lc,ql,qr);
		if(ql>mid)return query(rc,ql,qr);
		return query(lc,ql,mid)*query(rc,mid+1,qr);
	}
	inline pii query(int p,int k){
		if(T[p].l==T[p].r)return T[p].val();
		return query(k<=mid?lc:rc,k);
	}
}
inline pii ask(int p){
	int bt=bot[top[p]];
	if(p==bt)return SGT::query(1,num[p]);
	Mat upd=SGT::query(1,num[p],num[bt]-1);
	pii val=SGT::query(1,num[bt]),ret;
	ret.fi=max(M(upd[1][0],0ll),max(M(upd[1][1],val.fi),M(upd[1][2],val.se)));
	ret.se=max(M(upd[2][0],0ll),max(M(upd[2][1],val.fi),M(upd[2][2],val.se)));
	return ret;
}
inline void update(int p,int x){
	vl[p]=x,f[p][1]=g[p][1]+vl[p]+max(0ll,f[hson[p]][1]);
	while(1){
		int ft=fa[top[p]],tp=top[p];
		if(ft){
			pii upd=ask(tp);
			S[ft].del(max(upd.fi,upd.se));
			g[ft][1]-=max(0ll,upd.se);
		}
		SGT::update(1,num[p]);
		if(ft){
			pii upd=ask(tp);
			p=ft;
			S[p].push(max(upd.fi,upd.se));
			g[p][1]+=max(0ll,upd.se);
			g[p][0]=S[p].top();
			f[p][0]=max(g[p][0],max(f[hson[p]][0],f[hson[p]][1]));
			f[p][1]=vl[p]+g[p][1]+max(0ll,f[hson[p]][1]);
		}
		else break;
	}
}
char s[2];
int main(){
	n=read(),m=read();
	for(ri i=1;i<=n;++i)vl[i]=read(),S[i].push(0ll);
	for(ri i=1,u,v;i<n;++i)u=read(),v=read(),e[u].push_back(v),e[v].push_back(u);
	dfs1(1),dfs2(1,1),SGT::build(1,1,n);
	for(ri x;m;--m){
		scanf("%s",s);
		if(s[0]=='M')x=read(),update(x,read());
		else{
			pii ret=ask(read());
			cout<<max(ret.fi,ret.se)<<'\n';
		}
	}
	return 0;
}

2019.02.15 bzoj5210: 最大连通子块和(链分治+ddp)的更多相关文章

  1. bzoj5210 最大连通子块和 动态 DP + 堆

    题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=5210 题解 令 \(dp[x][0]\) 表示以 \(x\) 为根的子树中的包含 \(x\) ...

  2. bzoj5210最大连通子块和 (动态dp+卡常好题)

    卡了一晚上,经历了被卡空间,被卡T,被卡数组等一堆惨惨的事情之后,终于在各位大爹的帮助下过了这个题qwqqq (全网都没有用矩阵转移的动态dp,让我很慌张) 首先,我们先考虑一个比较基础的\(dp\) ...

  3. BZOJ5210 最大连通子块和 【树链剖分】【堆】【动态DP】

    题目分析: 解决了上次提到的<切树游戏>后,这道题就是一道模板题. 注意我们需要用堆维护子重链的最大值.这样不会使得复杂度变坏,因为每个重链我们只考虑一个点. 时间复杂度$O(nlog^2 ...

  4. bzoj5210最大连通子块和

    题解: 考虑朴素的dp:$$f_{u} = max(\sum_{v} f_{v} + w_{u} , 0)  \ \ \ \ h_{u} = max( max_{v} \{ h_{v} \}  , h ...

  5. 【BZOJ5210】最大连通子块和 树剖线段树+动态DP

    [BZOJ5210]最大连通子块和 Description 给出一棵n个点.以1为根的有根树,点有点权.要求支持如下两种操作: M x y:将点x的点权改为y: Q x:求以x为根的子树的最大连通子块 ...

  6. 【bzoj5210】最大连通子块和 树链剖分+线段树+可删除堆维护树形动态dp

    题目描述 给出一棵n个点.以1为根的有根树,点有点权.要求支持如下两种操作: M x y:将点x的点权改为y: Q x:求以x为根的子树的最大连通子块和. 其中,一棵子树的最大连通子块和指的是:该子树 ...

  7. 5210: 最大连通子块和 动态DP 树链剖分

    国际惯例的题面:这题......最大连通子块和显然可以DP,加上修改显然就是动态DP了......考虑正常情况下怎么DP:我们令a[i]表示选择i及i的子树中的一些点,最大连通子块和;b[i]表示在i ...

  8. 【bzoj5210】最大连通子块和 动态dp

    动态$dp$好题 考虑用树链剖分将整棵树剖成若干条链. 设x的重儿子为$son[x]$,设$x$所在链链头为$top[x]$ 对于重链上的每个节点(不妨设该节点编号为$x$)令$f[x]$表示以$x$ ...

  9. 纪中OJ 2019.02.15【NOIP提高组】模拟 B 组 梦回三国 比赛题解(第一个)

    声明 旁边的同学小 H(胡)对我说: “哟,比赛拿了 140,强!要知道,如果哥第三题 AC 了,哥就 230 了,你个废柴!!!(比赛实际分数 130 额呵)” 顿时,千万草泥马从我心中奔腾而过:你 ...

随机推荐

  1. 0003 - 基于xml的Spring Bean 的创建过程

    一.目录 前言 创建 Bean 容器 加载 Bean 定义 创建 Bean Spring Bean 创建过程中的设计模式 总结 二.前言 2.1 Spring 使用配置 ApplicationCont ...

  2. 刘志梅 201771010115 《面向对象程序设计(java)》 第七周学习总结

    实验七 继承附加实验 实验时间 2018-10-11 1.实验目的与要求 (1)进一步理解4个成员访问权限修饰符的用途: 即将类中的域标记为private,而方法标记为public.任何声明为priv ...

  3. 好看的java集合类图

    http://blog.csdn.net/iamzp2008/article/details/38151971?utm_source=tuicool&utm_medium=referral 现 ...

  4. Runtime 解读

    首先,第一个问题, 1>runtime实现的机制是什么,怎么用,一般用于干嘛? 这个问题我就不跟大家绕弯子了,直接告诉大家, runtime是一套比较底层的纯C语言API, 属于1个C语言库, ...

  5. Vue 封装的noData组件

    <template> <div :style="{color: fontColor}" :class="['noDataView', iconType] ...

  6. javac编译错误: 编码UTF8/GBK的不可映射字符

    转自:https://blog.csdn.net/leytton/article/details/52740171 Linux下为UTF-8编码,javac编译gbk编码的java文件时,容易出现“错 ...

  7. Python学习:模块初识、数据类型

    1.模块初识 在Python中,模块分为两种: (1)标准库 标准库无需安装,只要在使用的时候import就可以使用了 (2)第三方库 第三方库必须下载安装之后才能够引入使用 下面介绍两个基本的模块: ...

  8. Open SuSE 安装Python3.6

    1. 下载Python3.6 tar包 去除Modules/Setup文件167行的注释 readline readline.c -lreadline -ltermcap 2. 下载readline- ...

  9. leetcode11

    public class Solution { //public int MaxArea(int[] height) //{ // var max = 0; // for (int i = 0; i ...

  10. RTTI和反射小结

    Java有两种方式让我们在运行时识别对象和类的信息:1.“传统的”RTTI,假定所有的类型编译时已知:2.“反射”机制,允许在运行时发现和使用类的信息. 一.RTTI RTTI(Run-Time Ty ...