动态$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. Django(4)

    https://www.cnblogs.com/yuanchenqi/articles/7439088.html

  2. HDU 1087 Super Jumping! Jumping! Jumping! (DP+LIS)

    题意:给定一个长度为n的序列,让你求一个和最大递增序列. 析:一看,是不是很像LIS啊,这基本就是一样的,只不过改一下而已,d(i)表示前i个数中,最大的和并且是递增的, 如果 d(j) + a[i] ...

  3. POJ 2462 / HDU 1154 Cutting a Polygon

    就这样莫名其妙的过了,不过可以确定之前都是被精度卡死了.真心受不了精度问题了. 题意:一条直线在一个不规则多边形内的长度,包括边重合部分. 首先计算出所有交点,然后按想x,y的大小进行二级排序. 然后 ...

  4. 四则运算 Python实现(杨浩政,张兆敏)

    四则运算 GitHub仓库:https://github.com/15crmor/Arithmetic 项目要求: 题目:实现一个自动生成小学四则运算题目的命令行程序说明: 说明: 自然数:0, 1, ...

  5. Toad 实现 SQL 优化

    It is very easy for us to implement sql tuning by toad.  We need to do is just give complex sql stat ...

  6. visual studio code 中隐藏从 ts 文件生成的 js 文件和 map 文件

    typescript 文件编译产生的 js 和 map 文件不需要手工编辑,打开[文件][首选项][工作区设置],放入以下代码: // 将设置放入此文件中以覆盖默认值和用户设置. { "fi ...

  7. TransactionScope事务使用

    using (System.Transactions.TransactionScope T_Scope = new System.Transactions.TransactionScope()) { ...

  8. Dalsa线扫相机配置-一台工控机同时连接多个GigE相机

    如图,我强悍的工控机,有六个网口. 实际用的时候连了多台相机,为了偷懒我就把六个网口的地址分别设为192.168.0.1~192.168.0.6,以为相机的IP只要设在192.168.0这个网段然后随 ...

  9. DotNetty 使用ByteToMessageDecoder 国家部标808协议封装

    DotNetty 开源地址 https://github.com/Azure/DotNetty 个人博客地址   http://www.dncblogs.cn/Blog/ShowBlog/70 1.国 ...

  10. Winform打包安装程序覆盖安装的实现

    1.修改项目程序集版本号. 2.设置Version,使当前版本号大于前一个版本号. 3.RemovePreviousVersions属性设置为true. 以上三步后,生成安装程序即可实现覆盖安装. P ...