bzoj5210最大连通子块和
题解:
- 考虑朴素的dp:$$f_{u} = max(\sum_{v} f_{v} + w_{u} , 0) \ \ \ \ h_{u} = max( max_{v} \{ h_{v} \} , h_{u} )$$
- 考虑利用树剖修改:记$son_{u}$为$u$的重儿子,$g_{u}$为$u$所有轻儿子之和加$w_{u}$;
- 方程变成:
- $g_{u} = w_{u} + \sum_{v!=son_{u}} f_{v} $
- $f_{u} = max(f_{son_{u}}+ g_{u} , 0) $
- $h_{u} = max( max_{v} \{h_{v} \} , h_{u} )$
- 一个一个讨论:
- 首先$g$直接修改:当修改一个点时,$w_{u}$改变$g_{u}$改变,向上跳到轻链继续修改,这只有$log$次;
- 注意到$h$在一条重链上被写成了$g$的最大子段和,同时一个点的$f$就是$g$的最大左段和,这可以用线段树维护;
- 还需要维护用来统计答案的$h$,对每个点用一个堆记录轻儿子的$h$值,再把堆顶元素一起存到线段树里即可;
- 查询只需要查询一个点到链底的区间;
#include<bits/stdc++.h>
#define ll long long
#define ls (k<<1)
#define rs (k<<1|1)
using namespace std;
const int N=;
int n,m,w[N],sz[N],st[N],ed[N],fa[N],tp[N],sn[N],hd[N],o,idx,id[N];
ll f[N],g[N],h[N],s[N<<],sl[N<<],sr[N<<],ss[N<<],mx[N<<];
struct Edge{int v,nt;}E[N<<];
struct data{
priority_queue<ll>A,B;
void push(ll x){A.push(x);}
void pop(ll x){B.push(x);}
ll top(){
while(!B.empty()&&A.top()==B.top())A.pop(),B.pop();
return A.empty()?:A.top();
}
}q[N];
char gc(){
static char*p1,*p2,s[];
if(p1==p2)p2=(p1=s)+fread(s,,,stdin);
return(p1==p2)?EOF:*p1++;
}
int rd(){
int x=,f=;char c=gc();
while(c<''||c>''){if(c=='-')f=-;c=gc();}
while(c>=''&&c<=''){x=x*+c-'';c=gc();}
return x*f;
}
int gt(){
char c=gc();while(!isalpha(c))c=gc();
return c=='M';
}
void adde(int u,int v){
E[o]=(Edge){v,hd[u]};hd[u]=o++;
E[o]=(Edge){u,hd[v]};hd[v]=o++;
}
void dfs1(int u,int F){
sz[u]=;sn[u]=;
f[u]=w[u];
for(int i=hd[u];~i;i=E[i].nt){
int v=E[i].v;
if(v==F)continue;
dfs1(v,u);
fa[v]=u;
sz[u]+=sz[v];
f[u]+=f[v];
if(sz[v]>sz[sn[u]])sn[u]=v;
if(h[u]<h[v])h[u]=h[v];
}
if(f[u]<)f[u]=;
if(h[u]<f[u])h[u]=f[u];
}
void dfs2(int u,int T){
tp[u]=T;
id[st[u]=++idx]=u;
if(sn[u])dfs2(sn[u],T),ed[u]=ed[sn[u]];
else ed[u]=idx;
g[u]=w[u];
for(int i=hd[u];~i;i=E[i].nt){
int v=E[i].v;
if(v==fa[u]||v==sn[u])continue;
dfs2(v,v);
g[u]+=f[v];
q[u].push(h[v]);
}
}
void init(int k,int l){
ss[k]=g[id[l]];
mx[k]=q[id[l]].top();
s[k]=sl[k]=sr[k]=max(g[id[l]],0ll);
}
void pushup(int k){
mx[k]=max(mx[ls],mx[rs]);
s[k]=max(max(s[ls],s[rs]),sr[ls]+sl[rs]);
sl[k]=max(sl[ls],ss[ls]+sl[rs]);
sr[k]=max(sr[ls]+ss[rs],sr[rs]);
ss[k]=ss[ls]+ss[rs];
}
void build(int k,int l,int r){
if(l==r){init(k,l);return;}
int mid=(l+r)>>;
build(ls,l,mid);
build(rs,mid+,r);
pushup(k);
}
void update(int k,int l,int r,int x){
if(l==r){init(k,l);return;}
int mid=(l+r)>>;
if(x<=mid)update(ls,l,mid,x);
else update(rs,mid+,r,x);
pushup(k);
}
ll S,Sl,Sr,Mx,Ss;
void query(int k,int l,int r,int x,int y){
if(l==x&&r==y){
Mx=max(Mx,mx[k]);
S=max(max(S,s[k]),Sr+sl[k]);
Sl=max(Sl,Ss+sl[k]);
Sr=max(Sr+ss[k],sr[k]);
Ss=Ss+ss[k];
return ;
}
int mid=(l+r)>>;
if(y<=mid)query(ls,l,mid,x,y);
else if(x>mid)query(rs,mid+,r,x,y);
else query(ls,l,mid,x,mid),query(rs,mid+,r,mid+,y);
}
void Update(int x,int y){
int tx=tp[x];
g[x]-=w[x];g[x]+=(w[x]=y);
while(tx!=){
update(,,n,st[x]);
S=Sl=Sr=Ss=Mx=;
query(,,n,st[tx],ed[tx]);
if(Sl!=f[tx]){
g[fa[tx]]-=f[tx];
g[fa[tx]]+=(f[tx]=Sl);
}
Mx=max(Mx,S);
if(h[tx]!=Mx){
q[fa[tx]].pop(h[tx]);
q[fa[tx]].push(h[tx]=Mx);
}
x=fa[tx],tx=tp[x];
}
update(,,n,st[x]);
}
void Query(int x){
S=Sl=Sr=Ss=Mx=;
query(,,n,st[x],ed[x]);
Mx=max(Mx,S);
printf("%lld\n",Mx);
}
int main(){
// freopen("bzoj5210.in","r",stdin);
// freopen("bzoj5210.out","w",stdout);
n=rd();m=rd();
for(int i=;i<=n;++i)hd[i]=-,w[i]=rd();
for(int i=;i<n;++i)adde(rd(),rd());
dfs1(,);
dfs2(,);
build(,,n);
for(int i=,x,y;i<=m;++i){
if(gt())x=rd(),y=rd(),Update(x,y);
else x=rd(),Query(x);
}
return ;
}
bzoj5210最大连通子块和的更多相关文章
- 2019.02.15 bzoj5210: 最大连通子块和(链分治+ddp)
传送门 题意:支持单点修改,维护子树里的最大连通子块和. 思路: 扯皮: bzojbzojbzoj卡常差评. 网上的题解大多用了跟什么最大子段和一样的转移方法. 但是我们实际上是可以用矩阵转移的传统d ...
- bzoj5210 最大连通子块和 动态 DP + 堆
题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=5210 题解 令 \(dp[x][0]\) 表示以 \(x\) 为根的子树中的包含 \(x\) ...
- bzoj5210最大连通子块和 (动态dp+卡常好题)
卡了一晚上,经历了被卡空间,被卡T,被卡数组等一堆惨惨的事情之后,终于在各位大爹的帮助下过了这个题qwqqq (全网都没有用矩阵转移的动态dp,让我很慌张) 首先,我们先考虑一个比较基础的\(dp\) ...
- BZOJ5210 最大连通子块和 【树链剖分】【堆】【动态DP】
题目分析: 解决了上次提到的<切树游戏>后,这道题就是一道模板题. 注意我们需要用堆维护子重链的最大值.这样不会使得复杂度变坏,因为每个重链我们只考虑一个点. 时间复杂度$O(nlog^2 ...
- 【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为根的子树的最大连通子块和. 其中,一棵子树的最大连通子块和指的是:该子树 ...
- 5210: 最大连通子块和 动态DP 树链剖分
国际惯例的题面:这题......最大连通子块和显然可以DP,加上修改显然就是动态DP了......考虑正常情况下怎么DP:我们令a[i]表示选择i及i的子树中的一些点,最大连通子块和;b[i]表示在i ...
- 【bzoj5210】最大连通子块和 动态dp
动态$dp$好题 考虑用树链剖分将整棵树剖成若干条链. 设x的重儿子为$son[x]$,设$x$所在链链头为$top[x]$ 对于重链上的每个节点(不妨设该节点编号为$x$)令$f[x]$表示以$x$ ...
- bzoj 5210: 最大连通子块和【动态dp+树剖+线段树+堆】
参考:https://www.cnblogs.com/CQzhangyu/p/8632904.html 要开longlong的 首先看dp,设f[u]为必选u点的子树内最大联通块,p[u]为不一定选u ...
随机推荐
- 为centos虚拟机配置固定ip
在virtual上安装centos虚拟机以后,发现虚拟机没有ip,无法联网 将虚拟机的网络适配器改为桥接模式,桥接到物理机的无线网卡 为虚拟机配置固定IP(vi /etc/sysconfig/netw ...
- Windows环境下,从零开始搭建Nodejs+Express+Ejs框架(二)---安装Express,ejs
安装Express,ejs的前提是一定要先安装nodejs,具体安装方法请查看 http://www.cnblogs.com/tfiremeteor/p/8973105.html 安装Express和 ...
- jdk8 Optional使用详解
思考: 调用一个方法得到了返回值却不能直接将返回值作为参数去调用别的方法. 原来解决方案: 我们首先要判断这个返回值是否为null,只有在非空的前提下才能将其作为其他方法的参数.这正是一些类似Guav ...
- Windows下Visual Studio2017之AI环境搭建
本博客主要包含以下3点: AI简介及本博客主要目的 环境介绍及安装原因 搭建环境及检验是否安装成功 离线模型的训练 时间分配: 时间 时长(分钟) 收集资料+写博客 6.12 11:28-12:2 ...
- Daily Srum 10.21
到目前为止,我们组处在学习阶段,很多知识点都还不太清楚,所以现在我们还在看相关书籍和博客,任务. 而我们此间主要是在阅读一些材料: 陈谋一直在看学长的代码,其中C#的很多方式我都不太明白(尽管和Jav ...
- servlet几个常用的方法
servlet继承了HTTPServlet所以可以重写父类的方法,下面一 一介绍方法Dopost DoGet 比较常用不再介绍. 一.Init(),和Init(ServletConfig config ...
- BETA-1
前言 我们居然又冲刺了·一 团队代码管理github 站立会议 队名:PMS 530雨勤(组长) 过去两天完成了哪些任务 发现之前的代码居然已经有了陌生感,默默地复习一遍并做注释 阅读关于基于视频的车 ...
- python学习笔记05:贪吃蛇游戏代码
贪吃蛇游戏截图: 首先安装pygame,可以使用pip安装pygame: pip install pygame 运行以下代码即可: #!/usr/bin/env python import pygam ...
- 确保你想要修改的char*是可以修改的
void change(char *source) { source[] = 'D'; cout<<source<<endl; } 考虑一下,你有这么一个函数change它的作 ...
- 补发9.27“天天向上”团队Scrum站立会议
组长:王森 组员:张金生 张政 栾骄阳 时间:2016.09.27 地点:612寝 组员 已完成 未完成 王森 分析设计亮点 原型搭建 张金生 设计UI框架 美化完善 张政 学习C#语言初步应用 熟练 ...