【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为根的子树的最大连通子块和. 其中,一棵子树的最大连通子块和指的是:该子树 ...
随机推荐
- delphi XE7 数组操作中缺少的find(POS)功能
delphi xe7 中对数组操作做了很多扩充,比如加入了类似字符串处理的功能. 例如,数组相加 var A: array of integer; B: TBytes = [1,2,3,4]; //I ...
- 2018.07.01洛谷P2617 Dynamic Rankings(带修主席树)
P2617 Dynamic Rankings 题目描述 给定一个含有n个数的序列a[1],a[2],a[3]--a[n],程序必须回答这样的询问:对于给定的i,j,k,在a[i],a[i+1],a[i ...
- arduino uno r3 + SIM900 + USB打火机 实现电话触发点火
需求来源 1.儿子过完年6岁,喜欢玩烟花,但是胆子小,于是我就负责点火,从年前26到大年初八,每天晚上要给儿子点鞭炮啊点鞭炮. 2.这边过年要打关门炮跟开门炮,大年初一凌晨还要起来帮老妈点鞭炮,说实在 ...
- NSDictionary NSMutableDictionary NSSet NSMutableSet
//description只是返回了一个字符串 // [person description]; // //如果想要打印需要NSLog // NSLog(@"%@& ...
- React 组件的生命周期API和事件处理
一.简单记录React的组件的简洁的生命周期API: A:实例化期: 一个实例第一次被创建时所调用的API与其它后续实例被创建时所调用的API略有不同. 实例第一次被创建时会调用getDefaultP ...
- MVC 图片上传(转)
转自:http://www.cnblogs.com/Tiramisu/archive/2009/02/06/1385405.html MVC 上传图片 直接上代码: 页面:Index.aspx C ...
- 从问题域看hadoop的各种技术
近些年来Hadoop生态系统发展迅猛,它本身包含的软件越来越多,同时带动了周边系统的繁荣发展.尤其是在分布式计算这一领域,系统繁多纷杂,时不时冒出一个系统,号称自己比MapReduce或者Hive高效 ...
- Nonsense Alphabet
Nonsense Alphabet A was an ant Who seldom stood still, And who made a nice house In the side of a hi ...
- Alpha阶段项目复审(小小大佬带飞队)
Alpha阶段项目复审 小组的名字 优点 缺点,bug报告(至少140字) 最终名次(无并列) 只会嘤嘤嘤队 题材比较新颖!游戏和记单词的结合 有浏览器不兼容问题 5 GG队 样式新颖,自动导入好评 ...
- 用Java取指定时区的时间 北京时间,纽约时间,班加罗尔时间
/** * 取北京时间 * @return */ public static String getBeijingTime(){ return getFormatedDateString(8); } / ...