【bzoj5210】最大连通子块和 动态dp
动态$dp$好题
考虑用树链剖分将整棵树剖成若干条链。
设x的重儿子为$son[x]$,设$x$所在链链头为$top[x]$
对于重链上的每个节点(不妨设该节点编号为$x$)令$f[x]$表示以$x$为根的子树内(除以$son[x]$为根的子树),包含节点$x$的联通块的最大权值和。
我们求出一条重链上每个节点的f值后,考虑如何求出以$top[x]$为根的子树内的最大联通快。
我们考虑用线段树来合并每一个f值。我们用线段树维护四个值:
$sum$,该区间内所有$f$值的总和
$suml$,以该区间左端点为起点的所有区间中,权值最大区间权值。
$sumr$,以该区间右端点为七点的所有区间中,权值最大区间权值。
$ans$,该区间内所有区间的最大值
简单pushup一下就可以维护了。
考虑如何询问以x为根子树内的最大值,我们通过一遍dfs求出该树的dfs序,直接在线段树上查询即可。
注意n个INF相加可能会爆long long
#include<bits/stdc++.h>
#define M 400005
#define mid ((a[x].l+a[x].r)>>1)
#define L long long
#define INF (1LL<<50)
using namespace std; struct edge{int u,next;}e[M*]={}; int head[M]={},use=;
void add(L x,L y){use++;e[use].u=y;e[use].next=head[x];head[x]=use;}
L val[M]={},f[M]={},g[M]={};
int fa[M]={},siz[M]={},son[M]={},dfn[M]={},low[M]={},top[M]={},dn[M]={},rec[M]={},t=;
void dfs(L x){
siz[x]=; f[x]=val[x];
for(L i=head[x];i;i=e[i].next) if(e[i].u!=fa[x]){
fa[e[i].u]=x; dfs(e[i].u);
f[x]+=f[e[i].u];
g[x]=max(g[x],g[e[i].u]);
siz[x]+=siz[e[i].u];
if(siz[son[x]]<siz[e[i].u]) son[x]=e[i].u;
}
f[x]=max(f[x],0LL);
g[x]=max(g[x],f[x]);
}
void dfs(L x,L Top){
top[x]=Top; dfn[x]=++t; rec[t]=x;
if(son[x]) dfs(son[x],Top),dn[x]=dn[son[x]]; else dn[x]=x,t++;
for(L i=head[x];i;i=e[i].next) if(e[i].u!=fa[x]&&e[i].u!=son[x]) dfs(e[i].u,e[i].u);
low[x]=t;
} struct mat{
L ans,suml,sumr,sum;
mat(){suml=sumr=ans=sum=;}
mat(L Ans,L Suml,L Sumr,L Sum){ans=Ans; suml=Suml; sumr=Sumr; sum=Sum;}
friend mat operator *(mat a,mat b){
mat c;
c.ans=max(a.sumr+b.suml,max(a.ans,b.ans));
c.suml=max(a.suml,a.sum+b.suml);
c.sumr=max(a.sumr+b.sum,b.sumr);
c.sum=a.sum+b.sum;
c.sum=max(c.sum,-INF);
return c;
}
}wei[M]; struct seg{L l,r; mat a;}a[M<<];
void pushup(L x){a[x].a=a[x<<].a*a[x<<|].a;}
void build(L x,L l,L r){
a[x].l=l; a[x].r=r;
if(l==r){
L u=rec[l],sum=val[u];
if(u==){
a[x].a=mat(,,,-INF);
return;
}
for(L i=head[u];i;i=e[i].next)
if(e[i].u!=fa[u]&&e[i].u!=son[u]){
sum+=f[e[i].u];
}
a[x].a=wei[l]=mat(max(sum,0LL),max(sum,0LL),max(sum,0LL),sum);
return;
}
build(x<<,l,mid); build(x<<|,mid+,r);
pushup(x);
}
mat query(L x,L l,L r){
if(l<=a[x].l&&a[x].r<=r) return a[x].a;
if(r<=mid) return query(x<<,l,r);
if(mid<l) return query(x<<|,l,r);
return query(x<<,l,r)*query(x<<|,l,r);
}
mat query(L x){return query(,dfn[top[x]],dfn[dn[x]]);}
void updata(L x,L k){
if(a[x].l==a[x].r) return void(a[x].a=wei[k]);
if(k<=mid) updata(x<<,k); else updata(x<<|,k);
pushup(x);
} void Updata(L x,L Val){
L cha=Val-val[x]; val[x]=Val;
L hh=(wei[dfn[x]].sum+=cha);
wei[dfn[x]]=mat(max(hh,0LL),max(hh,0LL),max(hh,0LL),hh);
while(x){
mat last=query(x);
updata(,dfn[x]);
mat now=query(x);
x=fa[top[x]]; if(!x) return; cha=now.suml-last.suml;
hh=(wei[dfn[x]].sum+=cha);
wei[dfn[x]]=mat(max(hh,0LL),max(hh,0LL),max(hh,0LL),hh);
}
} L n,m;
main(){
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
scanf("%lld%lld",&n,&m);
for(L i=;i<=n;i++) scanf("%lld",val+i);
for(L i=,x,y;i<n;i++) scanf("%lld%lld",&x,&y),add(x,y),add(y,x);
dfs();
dfs(,);
build(,,t);
while(m--){
char op[]; L x,y;
scanf("%s%lld",op,&x);
if(op[]=='Q'){
mat hh=query(,dfn[x],low[x]);
printf("%lld\n",hh.ans);
}else{
scanf("%lld",&y);
Updata(x,y);
}
}
}
【bzoj5210】最大连通子块和 动态dp的更多相关文章
- bzoj5210 最大连通子块和 动态 DP + 堆
题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=5210 题解 令 \(dp[x][0]\) 表示以 \(x\) 为根的子树中的包含 \(x\) ...
- 5210: 最大连通子块和 动态DP 树链剖分
国际惯例的题面:这题......最大连通子块和显然可以DP,加上修改显然就是动态DP了......考虑正常情况下怎么DP:我们令a[i]表示选择i及i的子树中的一些点,最大连通子块和;b[i]表示在i ...
- bzoj 5210 最大连通子块和——动态DP
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=5210 似乎像bzoj4712一样,依然可以用别的方法做.但还是只写了动态DP. 当然是dp[ ...
- 2019.02.15 bzoj5210: 最大连通子块和(链分治+ddp)
传送门 题意:支持单点修改,维护子树里的最大连通子块和. 思路: 扯皮: bzojbzojbzoj卡常差评. 网上的题解大多用了跟什么最大子段和一样的转移方法. 但是我们实际上是可以用矩阵转移的传统d ...
- bzoj5210最大连通子块和 (动态dp+卡常好题)
卡了一晚上,经历了被卡空间,被卡T,被卡数组等一堆惨惨的事情之后,终于在各位大爹的帮助下过了这个题qwqqq (全网都没有用矩阵转移的动态dp,让我很慌张) 首先,我们先考虑一个比较基础的\(dp\) ...
- BZOJ5210 最大连通子块和 【树链剖分】【堆】【动态DP】
题目分析: 解决了上次提到的<切树游戏>后,这道题就是一道模板题. 注意我们需要用堆维护子重链的最大值.这样不会使得复杂度变坏,因为每个重链我们只考虑一个点. 时间复杂度$O(nlog^2 ...
- bzoj5210最大连通子块和
题解: 考虑朴素的dp:$$f_{u} = max(\sum_{v} f_{v} + w_{u} , 0) \ \ \ \ h_{u} = max( max_{v} \{ h_{v} \} , h ...
- 【BZOJ5210】最大连通子块和 树剖线段树+动态DP
[BZOJ5210]最大连通子块和 Description 给出一棵n个点.以1为根的有根树,点有点权.要求支持如下两种操作: M x y:将点x的点权改为y: Q x:求以x为根的子树的最大连通子块 ...
- 【bzoj5210】最大连通子块和 树链剖分+线段树+可删除堆维护树形动态dp
题目描述 给出一棵n个点.以1为根的有根树,点有点权.要求支持如下两种操作: M x y:将点x的点权改为y: Q x:求以x为根的子树的最大连通子块和. 其中,一棵子树的最大连通子块和指的是:该子树 ...
随机推荐
- TF Boys (TensorFlow Boys ) 养成记(二): TensorFlow 数据读取
TensorFlow 的 How-Tos,讲解了这么几点: 1. 变量:创建,初始化,保存,加载,共享: 2. TensorFlow 的可视化学习,(r0.12版本后,加入了Embedding Vis ...
- 45 The Effect of External Rewards on Behavior 外界奖励对行为的影响
The Effect of External Rewards on Behavior 外界奖励对行为的影响 ①Psychologists take opposing views on how exte ...
- java.sql.SQLException: null, message from server: "Host 'xxx' is not allowed to connect to this MySQL server"
java.sql.SQLException: null, message from server: "Host 'xxx' is not allowed to connect to thi ...
- HDU 2393 Higher Math (判断直角三角形)
题意:给定三个边,判断是不是直角三角形. 析:水题,勾股定理... 代码如下: #include <iostream> #include <cstdio> #include & ...
- LVDS_IP仿真分析
这个一个对tx_outclock移相180度后的仿真结果. tx_outclock的时钟沿与数据中心对齐. tx_coreclock时钟与inclock时钟频率相等,但有相差.
- MOD13A1: MODIS/Terra Vegetation Indices 16-Day L3 Global 500 m SIN Grid V006
https://lpdaac.usgs.gov/node/838 Description The MOD13A1 Version 6 product provides a Vegetation Ind ...
- python Cannot uninstall 'numpy'. It is a distutils installed project and thus we cannot accurately determine which files belong to it which would lead to only a partial uninstall.
在Python中移除(升级)numpy的时候出现: Cannot uninstall 'numpy'. It is a distutils installed project and thus we ...
- hdu1158 Employment Planning 2016-09-11 15:14 33人阅读 评论(0) 收藏
Employment Planning Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Othe ...
- NSUserDefaults用法详解
一.了解NSUserDefaults以及它可以直接存储的类型 NSUserDefaults是一个单例,在整个程序中只有一个实例对象,他可以用于数据的永久保存,而且简单实用,这是它可以让数据自由传递的一 ...
- telerik自定义皮肤的制作及用法
1. 打开telerik 官网 http://stylebuilder.telerik.com/ 2. 选择一个皮肤做为基础皮肤,并选择要制作的控件,并新取一个名字.比如选择皮肤Silk为基础皮肤,新 ...