[学习笔记]动态dp
其实就过了模板。
感觉就是带修改的dp
【模板】动态dp
给定一棵n个点的树,点带点权。
有m次操作,每次操作给定x,y表示修改点x的权值为y。
你需要在每次操作之后求出这棵树的最大权独立集的权值大小。
n,m<=1e5
参考题解:shadowice1984
n^2 DP简单又自然。
但是对于1e5次修改就不行了。
每一次修改会影响整个到根的链上的值。
采用树剖。
ldp[i][0/1]表示i选不选,对于所有的轻儿子dp值。
dp[i][0/1]表示i选不选,对于总共的所有儿子的dp值。
ldp[i][0]=∑max(ldp[lightson][1],ldp[lightson][0])
ldp[i][1]=∑ldp[lightson][0]
dp[i][0]=ldp[i][0]+max(dp[heavyson][1],dp[heavyson][0])
dp[i][1]=ldp[i][1]+dp[heavyson][0]
可以先把这个dp都求出来。
然后怎么维护?自然要用线段树维护dfs序。
采用矩阵。

a*b定义为:
c[i][j]=max(a[i][k]+b[k][j])
有结合律。
线段树维护区间矩阵乘积。(注意从右往左乘,自下而上)
只要在最前面乘上一个初始矩阵
第一行是0,第二行是-inf的矩阵。
就可以求出某个点的最终dp值了。
修改的时候,暴力修改这个 点的ldp0,ldp1
但是还会影响这个fa[top[x]]的ldp0,ldp1
所以要求出dp[top[x]],dp[top[y]]为了避免常数过大,
用一个数组记录dp值,然后把前后两次最大值的差值来修改fa[top[x]]的ldp0,ldp1
然后跳一条链,到fa[top[x]]
这样单次修改log^2n
每次返回max(dp[1][0],dp[1][1])
普通线段树版:(3000ms)
#include<bits/stdc++.h>
#define reg register int
#define il inline
#define numb (ch^'0')
#define mid ((l+r)>>1)
using namespace std;
typedef long long ll;
il void rd(int &x){
char ch;x=;bool fl=false;
while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);
for(x=numb;isdigit(ch=getchar());x=x*+numb);
(fl==true)&&(x=-x);
}
namespace Miracle{
const int N=1e5+;
const int inf=0x3f3f3f3f;
int n,m;
struct node{
int nxt,to;
}e[*N];
int hd[N],cnt;
void add(int x,int y){
e[++cnt].nxt=hd[x];
e[cnt].to=y;
hd[x]=cnt;
}
struct tr{
int a[][];
void init(int x,int y){//x:ldp0 y:ldp1
a[][]=x,a[][]=x;
a[][]=y,a[][]=-inf;
}
void pre(){
memset(a,-inf,sizeof a);
}
void st(){
a[][]=,a[][]=-inf,a[][]=-inf,a[][]=;
}
tr operator *(const tr& b){
tr c;c.pre();
for(reg i=;i<=;++i){
for(reg k=;k<=;++k){
for(reg j=;j<=;++j){
c.a[i][j]=max(c.a[i][j],a[i][k]+b.a[k][j]);
}
}
}return c;
}
void op(){
cout<<left<<setw()<<a[][]<<" "<<left<<setw()<<a[][]<<endl;
cout<<left<<setw()<<a[][]<<" "<<left<<setw()<<a[][]<<endl;
cout<<endl;
}
}s[N],t[*N],A;
int dfn[N],top[N],dfn2[N],fdfn[N],sz[N],dep[N],son[N];
int nd[N];//tot;//num of heavy chain
int fa[N];
int df;
int ldp[N][],dp[N][];
int w[N];
void dfs1(int x,int d){
dep[x]=d;
sz[x]=;
for(reg i=hd[x];i;i=e[i].nxt){
int y=e[i].to;
if(y==fa[x]) continue;
fa[y]=x;
dfs1(y,d+);
if(sz[y]>sz[son[x]]){
son[x]=y;
}
}
}
void dfs2(int x){
dfn[x]=++df;fdfn[df]=x;
if(!top[x]) {
top[x]=x;nd[top[x]]=x;
}
if(son[x]) top[son[x]]=top[x],nd[top[x]]=son[x],dfs2(son[x]); dp[x][]=w[x];
ldp[x][]=w[x];
for(reg i=hd[x];i;i=e[i].nxt){
int y=e[i].to;
if(y==son[x]||y==fa[x]) continue;
dfs2(y);
ldp[x][]+=max(dp[y][],dp[y][]);
ldp[x][]+=dp[y][];
}
if(son[x]){
dp[x][]=ldp[x][]+dp[son[x]][];
dp[x][]=ldp[x][]+max(dp[son[x]][],dp[son[x]][]);
}
s[x].init(ldp[x][],ldp[x][]);
}
void pushup(int x){
t[x]=t[x<<|]*t[x<<];
}
void build(int x,int l,int r){
if(l==r){
t[x]=s[fdfn[l]];return;
}
build(x<<,l,mid);build(x<<|,mid+,r);
pushup(x);
}
tr query(int x,int l,int r,int L,int R){
if(L<=l&&r<=R){
return t[x];
}
tr ret;ret.st();
if(mid<R) ret=ret*query(x<<|,mid+,r,L,R);
if(L<=mid) ret=ret*query(x<<,l,mid,L,R);
return ret;
}
void add(int x,int l,int r,int to,int p,int c){
if(l==r){
if(p) t[x].a[][]+=c;
else t[x].a[][]+=c,t[x].a[][]+=c;
return;
}
if(to<=mid) add(x<<,l,mid,to,p,c);
else if(mid<to) add(x<<|,mid+,r,to,p,c);
pushup(x);
}
int tmp[];
int to[];
int upda(int x,int y){
tmp[]=tmp[]=;
to[]=to[]=;
tmp[]=y-w[x];
w[x]=y;
while(x){
tr anc=A*query(,,n,dfn[top[x]],dfn[nd[top[x]]]);
to[]=anc.a[][],to[]=anc.a[][];
add(,,n,dfn[x],,tmp[]);
add(,,n,dfn[x],,tmp[]);
anc=A*query(,,n,dfn[top[x]],dfn[nd[top[x]]]);
tmp[]=max(anc.a[][],anc.a[][])-max(to[],to[]);
tmp[]=anc.a[][]-to[];
x=fa[top[x]];
}
tr ans=A*query(,,n,dfn[top[]],dfn[nd[top[]]]);
return max(ans.a[][],ans.a[][]);
}
int main(){
scanf("%d%d",&n,&m);
for(reg i=;i<=n;++i)rd(w[i]);
int x,y;
for(reg i=;i<=n-;++i){
rd(x);rd(y);add(x,y);add(y,x);
}
dfs1(,);
dfs2();
build(,,n);
A.a[][]=,A.a[][]=;
A.a[][]=-inf,A.a[][]=-inf;
while(m--){
rd(x);rd(y);
printf("%d\n",upda(x,y));
}
return ;
} }
int main(){
Miracle::main();
return ;
} /*
Author: *Miracle*
Date: 2018/11/12 16:29:49
*/
zkw线段树版:(1500ms)
#include<bits/stdc++.h>
#define reg register int
#define il inline
#define numb (ch^'0')
#define mid ((l+r)>>1)
using namespace std;
typedef long long ll;
il void rd(int &x){
char ch;x=;bool fl=false;
while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);
for(x=numb;isdigit(ch=getchar());x=x*+numb);
(fl==true)&&(x=-x);
}
namespace Miracle{
const int N=1e5+;
const int inf=0x3f3f3f3f;
int n,m;
struct node{
int nxt,to;
}e[*N];
int hd[N],cnt;
il void add(int x,int y){
e[++cnt].nxt=hd[x];
e[cnt].to=y;
hd[x]=cnt;
}
struct tr{
int a[][];
void init(int x,int y){//x:ldp0 y:ldp1
a[][]=x,a[][]=x;
a[][]=y,a[][]=-inf;
}
void pre(){
memset(a,-inf,sizeof a);
}
void st(){
a[][]=,a[][]=-inf,a[][]=-inf,a[][]=;
}
tr operator *(const tr& b) const{
tr c;c.pre();
for(reg i=;i<=;++i){
for(reg k=;k<=;++k){
for(reg j=;j<=;++j){
c.a[i][j]=max(c.a[i][j],a[i][k]+b.a[k][j]);
}
}
}return c;
}
void op(){
cout<<left<<setw()<<a[][]<<" "<<left<<setw()<<a[][]<<endl;
cout<<left<<setw()<<a[][]<<" "<<left<<setw()<<a[][]<<endl;
cout<<endl;
}
}s[N],t[*N],A;
int dfn[N],top[N],dfn2[N],fdfn[N],sz[N],dep[N],son[N];
int nd[N];//tot;//num of heavy chain
int fa[N];
int df;
int ldp[N][],dp[N][];
int w[N];
il void dfs1(int x,int d){
dep[x]=d;
sz[x]=;
for(reg i=hd[x];i;i=e[i].nxt){
int y=e[i].to;
if(y==fa[x]) continue;
fa[y]=x;
dfs1(y,d+);
if(sz[y]>sz[son[x]]){
son[x]=y;
}
}
}
il void dfs2(int x){
dfn[x]=++df;fdfn[df]=x;
if(!top[x]) {
top[x]=x;nd[top[x]]=x;
}
if(son[x]) top[son[x]]=top[x],nd[top[x]]=son[x],dfs2(son[x]); dp[x][]=w[x];
ldp[x][]=w[x];
for(reg i=hd[x];i;i=e[i].nxt){
int y=e[i].to;
if(y==son[x]||y==fa[x]) continue;
dfs2(y);
ldp[x][]+=max(dp[y][],dp[y][]);
ldp[x][]+=dp[y][];
}
if(son[x]){
dp[x][]=ldp[x][]+dp[son[x]][];
dp[x][]=ldp[x][]+max(dp[son[x]][],dp[son[x]][]);
}
s[x].init(ldp[x][],ldp[x][]);
}
int up;
il void build(){
up=;
for(;up<=n+;up<<=);
for(reg i=up;i<=up+up-;++i){
if(i>=up+&&i<=up+n) t[i]=s[fdfn[i-up]];
else t[i]=A;
}
for(reg i=up-;i;--i) t[i]=t[i<<|]*t[i<<];
}
il void chan(int to,int c0,int c1){
reg i=up+to;
t[i].a[][]+=c0;t[i].a[][]+=c0;
t[i].a[][]+=c1;
for(i>>=;i;i>>=){
t[i]=t[i<<|]*t[i<<];
}
// cout<<" after chan "<<endl;
}
il tr query(int l,int r){
tr le,ri;le.st();ri.st();
for(reg s=up+l-,e=up+r+;s^e^;s>>=,e>>=){
// cout<<s<<" "<<e<<endl;
if(!(s&)) le=t[s^]*le;
if(e&) ri=ri*t[e^];
}
return ri*le;
}
int tmp[];
int to[];
il int upda(int x,int y){
tmp[]=tmp[]=;
to[]=to[]=;
tmp[]=y-w[x];
w[x]=y;
while(x){
//tr anc=A*query(1,1,n,dfn[top[x]],dfn[nd[top[x]]]);
to[]=dp[top[x]][],to[]=dp[top[x]][];
chan(dfn[x],tmp[],tmp[]);
tr anc=A*query(dfn[top[x]],dfn[nd[top[x]]]);
tmp[]=max(anc.a[][],anc.a[][])-max(to[],to[]);
tmp[]=anc.a[][]-to[];
dp[top[x]][]=anc.a[][],dp[top[x]][]=anc.a[][];
x=fa[top[x]];
}
return max(dp[][],dp[][]);
}
int main(){
scanf("%d%d",&n,&m);
for(reg i=;i<=n;++i)rd(w[i]);
int x,y;
for(reg i=;i<=n-;++i){
rd(x);rd(y);add(x,y);add(y,x);
}
dfs1(,);
dfs2();
A.a[][]=,A.a[][]=;
A.a[][]=-inf,A.a[][]=-inf;
build();
while(m--){
rd(x);rd(y);
printf("%d\n",upda(x,y));
}
return ;
} }
int main(){
// freopen("data.in","r",stdin);
// freopen("my.out","w",stdout);
Miracle::main();
return ;
} /*
Author: *Miracle*
Date: 2018/11/12 16:29:49
*/
[学习笔记]动态dp的更多相关文章
- WPF-学习笔记 动态修改控件Margin的值
原文:WPF-学习笔记 动态修改控件Margin的值 举例说明:动态添加一个TextBox到Grid中,并设置它的Margin: TextBox text = new TextBox(); t_gri ...
- Java学习笔记——动态代理
所谓动态,也就是说这个东西是可变的,或者说不是一生下来就有的.提到动态就不得不说静态,静态代理,个人觉得是指一个代理在程序中是事先写好的,不能变的,就像上一篇"Java学习笔记——RMI&q ...
- Angular 学习笔记 (动态组件 & Material Overlay & Dialog 分析)
更新: 2019-11-24 dialog vs router link refer : https://stackoverflow.com/questions/51821766/angular-m ...
- [学习笔记]整体DP
问题: 有一些问题,通常见于二维的DP,另一维记录当前x的信息,但是这一维过大无法开下,O(nm)也无法通过. 但是如果发现,对于x,在第二维的一些区间内,取值都是相同的,并且这样的区间是有限个,就可 ...
- [学习笔记] 数位DP的dfs写法
跟着洛谷日报走,算法习题全都有! 嗯,没错,这次我也是看了洛谷日报的第84期才学会这种算法的,也感谢Mathison大佬,素不相识,却写了一长篇文章来帮助我学习这个算法. 算法思路: 感觉dfs版的数 ...
- 学习笔记-动态树Link-Cut-Tree
--少年你有梦想吗? --少年你听说过安利吗? 安利一个集训队讲解:http://wenku.baidu.com/view/75906f160b4e767f5acfcedb 关于动态树问题,有多种方法 ...
- [WPF学习笔记]动态加载XAML
好久没写Blogs了,现在在看[WPF编程宝典],决定开始重新写博客,和大家一起分享技术. 在编程时我们常希望界面是动态的,可以随时变换而不需要重新编译自己的代码. 以下是动态加载XAML的一个事例代 ...
- 单片机C语言开发学习笔记---动态的数码管
在郭天祥的那本书中,有一个通过按键控制数码管的例子,在运行这个例子的时候,我发现当按键按下的时候,第一位数码管会熄掉,这是为什么呢? 后来在网上找到了原因,当我按下按键不松开的时候,接下来要运行的代码 ...
- EXCEL 2010学习笔记—— 动态图表
今天梳理一下动态图表的相关内容,做一个简单的整理 关键的操作点: 1.插入动态控制器:开发工具->插入->表单控件 对控件进行修改 右键 设置控件格式->单元格链接 用来作为if ...
随机推荐
- php Trait的使用
1.php中的trait是啥? 看上去既像类又像接口,其实都不是,Trait可以看做类的部分实现,可以混入一个或多个现有的PHP类中,其作用有两个:表明类可以做什么:提供模块化实现.Trait是一种代 ...
- Hadoop(6)-HDFS的shell操作
1.基本语法 使用 hadoop fs 具体命令 或者 hdfs dfs 具体命令 hadoop命令的shell源码 hdfs命令的shell源码 由此可见,这两个命令最后都是执行的一个jav ...
- Could not obtain transaction-synchronized Session for current thread 错误的解决方法!
BsTable bsTable = new BsTable(); // String time = request.getParameter("date"); String tim ...
- Qt on Android 蓝牙通信开发
版权声明:本文为MULTIBEANS ORG研发跟随文章,未经MLT ORG允许不得转载. 最近做项目,需要开发安卓应用,实现串口的收发,目测CH340G在安卓手机上非常麻烦,而且驱动都是Java版本 ...
- Java学习笔记十一:Java中的方法
Java中的方法 一:什么是方法: 所谓方法,就是用来解决一类问题的代码的有序组合,是一个功能模块. 学过C语言或者其他语言的应该都知道函数这个东西,在Java中,其实方法就是函数,只不过叫法不同,在 ...
- centos 7 关闭IPtables
systemctl status iptables.service systemctl stopiptables.service
- 在Android studio中用gradle打 jar 包(Mac下)
这两天公司要重构项目,以前的项目在eclipse上,准备迁移到Android studio上,需要对项目打包,于是我学习了Android studio中gradle打包的内容.我在公司用的Mac,在家 ...
- Android开发——告诉你Adapter应该写在Activity里面还是外面
0. 前言 本文转载自AItsuki的博客. 首先说明一下为什么要写这么一篇博客:最近看了一些其他人的项目,发现很多项目的做法是建立一个专门存放Adapter类的Package包,也有的项目干脆直接都 ...
- centos下搭建svn服务器端/客户端
1.安装 yum install subversion httpd mod_dav_svn 2.创建仓库存储代码 mkdir /var/repos svnadmin create /var/repos ...
- linux命令大全(转载)
在搭建openstack时遇到问题,导致上网查询相关信息.找到一篇不错的文章,希望对大家有用.下附地址: http://blog.csdn.net/junbujianwpl/article/detai ...