动态$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. 情感分析snownlp包部分核心代码理解

    snownlps是用Python写的个中文情感分析的包,自带了中文正负情感的训练集,主要是评论的语料库.使用的是朴素贝叶斯原理来训练和预测数据.主要看了一下这个包的几个主要的核心代码,看的过程作了一些 ...

  2. KbmMW 服务器架构简介

    kbmmw 由于文档比较少,很多同学开始用时很难理解.一直准备写一个关于kbmmw 架构的东西. 这几天与红鱼儿(blog)研究服务器线程时,整理了一下,大概画了一下kbmmw (版本4.5)服务器的 ...

  3. * 结束Activity

    public class MainActivity extends Activity   {       @Override       public void onCreate(Bundle sav ...

  4. CentOS中的一些小技巧和特殊知识

    一:软件: firefox 1.在tab栏右键可以打开上一次关闭的标签. 2.在上面的搜索栏可以添加搜索引擎,这样就不需要再打开标签页访问搜索引擎主页来搜索了. 3.获取firefox下载弹框的资源U ...

  5. SceneControl+AE+鼠标滚轮缩放

    要为SceneControl设置鼠标滚轮缩放必须定义委托,因为SceneControl没有Wheel事件,所以委托From的Wheel事件 public Form1() { InitializeCom ...

  6. hbase使用MapReduce操作3(实现将 fruit 表中的一部分数据,通过 MR 迁入到 fruit_mr 表中)

    Runner类 实现将 fruit 表中的一部分数据,通过 MR 迁入到 fruit_mr 表中. package com.yjsj.hbase_mr; import org.apache.hadoo ...

  7. [label][politic-video]李锡锟的政治学视频下载链接

    李锡锟政治学 1.http://r15---sn-p5qlsn7y.googlevideo.com/videoplayback?initcwndbps=1471000&signature=09 ...

  8. colorbox在android上由于高度太高无法scroll问题

    首先看问题截图: 我们可以看到弹出的colorbox页面的高度已经到了下面,你根本看不到"mistake cross"<=>"X". 我测试了iph ...

  9. leetcode-爬楼梯(动态规划)

    假设你正在爬楼梯.需要 n 阶你才能到达楼顶. 每次你可以爬 1 或 2 个台阶.你有多少种不同的方法可以爬到楼顶呢? 注意:给定 n 是一个正整数. 示例 1: 输入: 2 输出: 2 解释: 有两 ...

  10. PostgreSQL 用户和权限管理

    PostgreSQL 用户和权限管理 创建 CREATE ROLE rolename;CREATE USER username;CREATE USER和CREATE ROLE的区别在于,CREATE ...