动态$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的更多相关文章

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

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

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

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

  3. bzoj 5210 最大连通子块和——动态DP

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=5210 似乎像bzoj4712一样,依然可以用别的方法做.但还是只写了动态DP. 当然是dp[ ...

  4. 2019.02.15 bzoj5210: 最大连通子块和(链分治+ddp)

    传送门 题意:支持单点修改,维护子树里的最大连通子块和. 思路: 扯皮: bzojbzojbzoj卡常差评. 网上的题解大多用了跟什么最大子段和一样的转移方法. 但是我们实际上是可以用矩阵转移的传统d ...

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

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

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

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

  7. bzoj5210最大连通子块和

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

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

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

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

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

随机推荐

  1. chrome,opera..通过file协议浏览html代码时,发送的ajax请求本地文件,会报跨域错误

    XMLHttpRequest cannot loadfile:///E:/webs/extJS/ext-3.3.0/examples/csdn/combobox.txt?_dc=14147389739 ...

  2. MySQL 的IFNULL()、ISNULL()和NULLIF()函数

    参考与http://blog.csdn.net/xingyu0806/article/details/52080962 IFNULL(expr1,expr2) 假如expr1不为NULL,则 IFNU ...

  3. gj4 深入类和对象

    4.1 鸭子类型和多态 当看到一只鸟走起来像鸭子.游永起来像鸭子.叫起来也像鸭子,那么这只鸟就可以被称为鸭子 只要利用Python的魔法函数,就能实现某些Python数据类型的类似的方法. class ...

  4. C#操作Excel(创建、打开、读写、保存)几种方法的总结

    在.NET开发中,不管是web程序还是桌面软件(尤其是涉及数据库操作的MIS系统等),常常需操作Excel,如导出数据到Excel,读取Excel中数据到程序中等.总结起来,其操作不外乎创建.打开.读 ...

  5. org.springframework spring-test

    需要的jar包 <dependency> <groupId>org.springframework</groupId> <artifactId>spri ...

  6. 团队合作项目—(GG队)

    团队展示 一.队名:GG 二.队员信息 队员 学号 叶尚文(队长) 3116008802 蔡晓晴 3216008808 杜婷萱 3216008809 龙剑初 3116004647 于泽浩 311600 ...

  7. 纸壳CMS可视化建站系统搭建多语言网站

    纸壳CMS是可视化建站系统,现已经从架构上支持多语言.但是多语言功能默认是没有开启的.您可以从设置中开启多语言,或者随时关闭它,您可以随时进行切换. 开启多语言 如果您没有在系统设置中看到多语言设置菜 ...

  8. MVVM Light 新手入门(3) :ViewModel / Model 中定义“事件” ,并在View中调用 (无参数调用)

    今天学习MVVM架构中“事件”的添加并调用,特记录如下,学习资料均来自于网络,特别感谢翁智华 的 利刃 MVVMLight 6:命令基础 在MVVM Light框架中,事件是WPF应用程序中UI与后台 ...

  9. C#操作Xml树的扩展类

    本文提供一个操作Xml树的扩展类,与将xml字符串直接映射成实体对象的使用方法,供大家参考,学习. 下面附上源码 using System; using System.Collections.Gene ...

  10. 如何学习、了解Kubernetes?

    欢迎访问网易云社区,了解更多网易技术产品运营经验 [Kubernetes官方文档](https://kubernetes.io/docs/tutorials/)是最基本的入门教材,这里的内容是最官方, ...