洛谷4719 【模板】动态dp
题目:https://www.luogu.org/problemnew/show/P4719
关于动态DP似乎有猫锟的WC2018论文,但找不见;还是算了。
http://immortalco.blog.uoj.ac/archive
动态DP大概就是求这样的问题。
把轻儿子对自己的转移值写进矩阵 g 里,重新定义一下乘法运算,自己的值矩阵 f 就是重儿子的 f 乘上自己的 g 了。
树剖的线段树维护区间内的那些 g 的连乘积,则从自己开始到自己所在重链的底端这一段的 g 连乘就是自己的 f 了(因为底端是叶子,所以本来该乘一个 f ,就和不乘一样了)。
修改的时候就是改一些 g 。自己如果在 x 的轻儿子里,则需要改一下 x 的 g 。一次会改 log 个 g 。
求答案就是 1 所在重链的连乘积。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ls Ls[cr]
#define rs Rs[cr]
using namespace std;
const int N=1e5+,INF=1e9+;
int n,m,w[N],hd[N],xnt,to[N<<],nxt[N<<],tot,Ls[N<<],Rs[N<<];
int dfn[N],siz[N],son[N],rnk[N],dep[N],fa[N],top[N],bj[N],dp[N][];
int Mx(int a,int b){return a>b?a:b;}
struct Matrix{
int a[][];
Matrix(){a[][]=a[][]=a[][]=a[][]=-INF;}
Matrix operator+ (const Matrix &b)const
{
Matrix c;
for(int i=;i<=;i++)
for(int k=;k<=;k++)
for(int j=;j<=;j++)
c.a[i][j]=Mx(c.a[i][j],a[i][k]+b.a[k][j]);
return c;
}
}g[N],t[N<<];
int rdn()
{
int ret=;bool fx=;char ch=getchar();
while(ch>''||ch<''){if(ch=='-')fx=;ch=getchar();}
while(ch>=''&&ch<='') ret=(ret<<)+(ret<<)+ch-'',ch=getchar();
return fx?ret:-ret;
}
void add(int x,int y){to[++xnt]=y;nxt[xnt]=hd[x];hd[x]=xnt;}
void dfs(int cr)
{
dep[cr]=dep[fa[cr]]+; siz[cr]=;
for(int i=hd[cr],v;i;i=nxt[i])
if((v=to[i])!=fa[cr])
{
fa[v]=cr; dfs(v);
siz[cr]+=siz[v];
siz[v]>siz[son[cr]]?son[cr]=v:;
}
}
void dfsx(int cr)
{
dfn[cr]=++tot; rnk[tot]=cr;
dp[cr][]=; dp[cr][]=w[cr];
if(son[cr])
{
top[son[cr]]=top[cr];dfsx(son[cr]);
dp[cr][]+=Mx(dp[son[cr]][],dp[son[cr]][]);
dp[cr][]+=dp[son[cr]][];
}
g[cr].a[][]=g[cr].a[][]=;
g[cr].a[][]=w[cr]; g[cr].a[][]=-INF;
if(!son[cr]){ bj[top[cr]]=tot; return;}
for(int i=hd[cr],v;i;i=nxt[i])
if((v=to[i])!=fa[cr]&&v!=son[cr])
{
top[v]=v; dfsx(v);
dp[cr][]+=Mx(dp[v][],dp[v][]); dp[cr][]+=dp[v][];
g[cr].a[][]+=Mx(dp[v][],dp[v][]); g[cr].a[][]=g[cr].a[][];
g[cr].a[][]+=dp[v][];
}
}
void build(int l,int r,int cr)
{
if(l==r){t[cr]=g[rnk[l]];return;}
int mid=l+r>>;
ls=++tot; build(l,mid,ls);
rs=++tot; build(mid+,r,rs);
t[cr]=t[ls]+t[rs];
}
void updt(int l,int r,int cr,int p)
{
if(l==r){t[cr]=g[rnk[l]];return;}
int mid=l+r>>;
if(p<=mid)updt(l,mid,ls,p);
else updt(mid+,r,rs,p);
t[cr]=t[ls]+t[rs];
}
Matrix query(int l,int r,int cr,int L,int R)
{
if(l>=L&&r<=R)return t[cr];
int mid=l+r>>;
if(R<=mid)return query(l,mid,ls,L,R);
if(mid<L) return query(mid+,r,rs,L,R);
return query(l,mid,ls,L,R)+query(mid+,r,rs,L,R);
}
Matrix calc(int cr){ return query(,n,,dfn[cr],bj[cr]);}
void cz(int x,int y)
{
g[x].a[][]+=y-w[x]; w[x]=y;
Matrix k1=calc(top[x]); updt(,n,,dfn[x]); Matrix k2=calc(top[x]);
while(fa[top[x]])
{
int d=fa[top[x]];
g[d].a[][]+=Mx(k2.a[][],k2.a[][])-Mx(k1.a[][],k1.a[][]);
g[d].a[][]=g[d].a[][];
g[d].a[][]+=k2.a[][]-k1.a[][];
x=d;
k1=calc(top[x]); updt(,n,,dfn[x]); k2=calc(top[x]);
}
}
int main()
{
n=rdn();m=rdn();
for(int i=;i<=n;i++)w[i]=rdn();
for(int i=,u,v;i<n;i++)
{
u=rdn(); v=rdn(); add(u,v); add(v,u);
}
dfs(); top[]=; dfsx(); tot=; build(,n,);//tot=1!!!!!!
for(int i=,x,y;i<=m;i++)
{
x=rdn(); y=rdn(); cz(x,y);
Matrix d=calc();
printf("%d\n",Mx(d.a[][],d.a[][]));
}
return ;
}
洛谷4719 【模板】动态dp的更多相关文章
- 【洛谷4719】 动态dp(树链剖分,dp,矩阵乘法)
前言 其实我只是为了过掉模板而写的ddp,实际应用被吊着锤 Solution 并不想写详细的过程 一句话过程:将子树中轻儿子的贡献挂到这个点上面来 详细版:(引用yyb) 总结一下的话,大致的过程是这 ...
- 【洛谷P4719】动态dp 动态dp模板
题目大意:给你一颗$n$个点的树,点有点权,有$m$次操作,每次操作给定$x$,$y$,表示修改点$x$的权值为$y$. 你需要在每次操作之后求出这棵树的最大权独立集的权值大小. 数据范围:$n,m≤ ...
- [luogu 4719][模板]动态dp
传送门 Solution \(f_{i,0}\) 表示以i节点为根的子树内,不选i号节点的最大独立集 \(f_{i,1}\)表示以i节点为根的子树内,选i号节点的最大独立集 \(g_{i,0}\) 表 ...
- 洛谷P3373 [模板]线段树 2(区间增减.乘 区间求和)
To 洛谷.3373 [模板]线段树2 题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某区间每一个数加上x 2.将某区间每一个数乘上x 3.求出某区间每一个数的和 输入输出格式 输入格 ...
- 洛谷4719 【模板】动态dp 学习笔记(ddp 动态dp)
qwq大概是混乱的一个题. 首先,还是从一个比较基础的想法开始想起. 如果每次暴力修改的话,那么每次就可以暴力树形dp 令\(dp[x][0/1]\)表示\(x\)的子树中,是否选择\(x\)这个点的 ...
- LCT总结——概念篇+洛谷P3690[模板]Link Cut Tree(动态树)(LCT,Splay)
为了优化体验(其实是强迫症),蒟蒻把总结拆成了两篇,方便不同学习阶段的Dalao们切换. LCT总结--应用篇戳这里 概念.性质简述 首先介绍一下链剖分的概念(感谢laofu的讲课) 链剖分,是指一类 ...
- 洛谷P3928 Sequence2(dp,线段树)
题目链接: 洛谷 题目大意在描述底下有.此处不赘述. 明显是个类似于LIS的dp. 令 $dp[i][j]$ 表示: $j=1$ 时表示已经处理了 $i$ 个数,上一个选的数来自序列 $A[0]$ 的 ...
- 洛谷P2224 [HNOI2001] 产品加工 [DP补完计划,背包]
题目传送门 产品加工 题目描述 某加工厂有A.B两台机器,来加工的产品可以由其中任何一台机器完成,或者两台机器共同完成.由于受到机器性能和产品特性的限制,不同的机器加工同一产品所需的时间会不同,若同时 ...
- 洛谷P1108 低价购买[DP | LIS方案数]
题目描述 “低价购买”这条建议是在奶牛股票市场取得成功的一半规则.要想被认为是伟大的投资者,你必须遵循以下的问题建议:“低价购买:再低价购买”.每次你购买一支股票,你必须用低于你上次购买它的价格购买它 ...
随机推荐
- python中编写无参数decorator
Python的 decorator 本质上就是一个高阶函数,它接收一个函数作为参数,然后,返回一个新函数. 使用 decorator 用Python提供的 @ 语法,这样可以避免手动编写 f = de ...
- [NOI2008]奥运物流
题目 洛谷 BZOJ 做法 单环有向图毒瘤题 不考虑环和改变后继:\(\sum\limits{i=1}^n C_i\cdot K^{dep(i)}\) 考虑环无穷等比求极m:\(R(1)=\sum\l ...
- R的几个基础函数
本章目录: 1.路径和文件 2.数据转换 3.获得帮助 路径和文件: 1.工作路径: 显示当前路径:getwd() 设置路径:setwd(“绝对路径”) 2.目录: 创建目录:dir.create(& ...
- String和StringBuilder、StringBuffer
Java平台提供了两种类型的字符串:String和StringBuffer/StringBuilder String 只读字符串,这里的只读并不是指String类型变量无法被修改,而是指String类 ...
- 39条常见的linux系统管理面试题
1.如何看当前Linux系统有几颗物理CPU和每颗CPU的核数? 答:[root@centos6 ~ 10:55 #35]# cat /proc/cpuinfo|grep -c 'physical i ...
- centos下安装Anaconda
第一步:将下载好的Anaconda2-4.1.1-Linux-x86_64.sh软件传到linux下 第二步:[hadoop@spark1 ~]$ cd Desktop #进入到该软件所在目录,我的放 ...
- HDFS数据流-剖析文件读取及写入
HDFS数据流-剖析文件读取及写入 文件读取 1. 客户端通过调用FileSystem对象的open方法来打开希望读取的文件,对于HDFS来说,这个对象是分布式文件系统的一个实例.2. Distrib ...
- tensorflow笔记:多层CNN代码分析
tensorflow笔记系列: (一) tensorflow笔记:流程,概念和简单代码注释 (二) tensorflow笔记:多层CNN代码分析 (三) tensorflow笔记:多层LSTM代码分析 ...
- linux---mysql忘记密码
二.忘记原来的myql的root的密码: 首先,你必须要有操作系统的root权限了.要是连系统的root权限都没有的话,先考虑root系统再走下面的步骤.类似于安全模式登录系统,有人建议说是pkill ...
- hdu6237 分解质因子
题意:给一堆石子,每次移动一颗到另一堆,要求最小次数使得,所有石子数gcd>1 题解:枚举所有质因子,然后找次数最小的那一个,统计次数时,我们可以事先记录下每堆石子余质因子 的和,对所有石子取余 ...