动态dp

article/2025/10/11 8:31:36

以前学树型dp留下的题目,没有写,然后过了几个月后又回来写了这道题

战略游戏
这是一道典型的最小点覆盖的模板,蒟蒻采用的是树型dp的做法
\(f[i][0/1]\) 在以 \(i\) 为根的子树中,选或不选当前这个点所需要的最少的点
那么转移方程为:
\(f[i][0]=\sum_{v\in son[i]} f[v][1]\)
\(f[i][1]=\sum_{v\in son[i]} min(f[v][0],f[v][1])+1\)
图片解释:
战略游戏1.png
战略游戏.png

然后我们从根节点开始,\(dfs\) 遍历每一个节点,然后在每次遍历完一个节点后进行一次树型 \(dp\) ,注意,这个过程是从叶子结点到根的。
\(Code:\)

#include <iostream>
#include <cstdio>
using namespace std;
struct Node
{int t;int next;   
}node[30011];
int n,tot;
int f[3011][2],head[3011];
void add(int x,int y)
{node[++tot].t=y;node[tot].next=head[x];head[x]=tot;return;
}
void dfs(int u,int fa)
{f[u][1]=1; //f[u][1]要初始化为1,因为它要选上自己这个点for(int i=head[u];i;i=node[i].next){int v=node[i].t;if(v!=fa) {dfs(v,u);f[u][0]+=f[v][1]; //如上面的转移方程f[u][1]+=min(f[v][1],f[v][0]);  }   }   
} 
int main()
{
//  freopen(".in","r",stdin);
//  freopen(".out","w",stdout);scanf("%d",&n);for(int i=1;i<=n;++i){int step;scanf("%d",&step);  ++step;int k;scanf("%d",&k);for(int j=1;j<=k;++j){int y;scanf("%d",&y);++y;add(step,y);add(y,step);  //因为题目中的标号是0~n-1,我为了方便就将每个节点加了1} }dfs(1,0);printf("%d",min(f[1][0],f[1][1]));return 0;
}

但是,如果我们加上一个修改操作,每一次都进行修改,然后询问 \(dp\)值,这应该怎么做呢?
这就需要用到我们的标题:动态\(dp\) 了。
动态dp
这道题目要求的是最大点权独立集权值,我们把上面的方程稍微改一下,注意,是独立集,不是覆盖集
\(f[i][0]=\sum_{v\in son[i]} max(f[v][0],f[v][1])\)
\(f[i][1]=\sum_{v\in son[i]} f[v][0]+a[i]\)
图片解释:
动态dp.png
动态dp1.png
注:\(a[i]\) 表示节点 \(i\) 的权值
我们首先回想一下矩阵乘法的式子:
\(C_{i,j}=\sum_{k=1}^{p}A_{i,k}* B_{k,j}\)
然后我们来脑补一下\(floyd\) 的转移方程:
\(f_{i,j}=min_{k=1}^{n}f_{i,k}+f_{k,j}\)
嗯,为什么看起来这么相似呢?
好像只是把\(\sum\) 换成了\(min\) ,$* $ 改成了 \(+\) 啊,这样子的矩阵乘法是对的吗?
答案是 \(YES\)
这时候我们就可以想到一种方法,我们能不能把转移方程改写成这种新定义的矩阵乘法的形式,然后用线段树来维护一段区间的矩阵乘法的乘积,从而实现 \(nlogn\) 的时间复杂度呢?
答案是 \(Right!\)
但是,我们上面的转移方程不好直接写成矩阵乘法的形式,我们将它改变一下:
\(g[i][0/1]\) 表示不包含\(i\)处在的重链上的节点(包括 \(i\)
\(g[i][0]=\sum_{v\neq son[i]} max(f[v][0],f[v][1])\)
\(g[i][1]=\sum_{v\neq son[i]} f[v][0]+a[i]\)
那么原来的转移方程就可以改为:
\(f[i][0]=g[x][0]+max(f[son[i][0],f[son[i]][1])\)
$f[i][1]=g[x][1]+f[son[i][0] $
改写成矩阵乘法的形式就是:
\[\begin{vmatrix}g_{x,0}&g_{x,0}\\g_{x,1}&-\infty\end{vmatrix}\cdot\begin{vmatrix}f_{son[i],0}\\f_{son[i],1}\end{vmatrix}=\begin{vmatrix}f_{x,0}\\f_{x,1}\end{vmatrix}\]
这里我用的是 \(LCT\) 的写法,复杂度为 \(mlogn\) ,当然也有树链剖分的写法,复杂度为 \(mlog^2n\)
\(Code:\)

#include <iostream>
#include <cstdio>
#define inf 1<<30
#define R register int 
#define I inline void
#define lc c[x][0]
#define rc c[x][1]
#define N 100011
using namespace std;
struct Matrix
{long long data[2][2];Matrix(){data[0][0]=data[0][1]=data[1][0]=data[1][1]=-inf;}
};
struct Node
{int t;int next;
}node[N<<1];
int a[N],f[N],c[N][2],head[N],dp[N][2],st[N];
Matrix val[N],prd[N];
int n,m,tot=0;
I add(int x,int y)
{node[++tot].t=y;node[tot].next=head[x];head[x]=tot;
}
inline Matrix mul(const Matrix &A,const Matrix &B)
{Matrix C;for(int k=0;k<=1;++k)for(int i=0;i<=1;++i)for(int j=0;j<=1;++j)C.data[i][j]=max(C.data[i][j],A.data[i][k]+B.data[k][j]); //注意,这里的矩阵乘法是重定义后的return C;
}
inline bool nroot(R x)
{return (c[f[x]][0]==x)||(c[f[x]][1]==x);
}
inline int chk(R x)
{return c[f[x]][1]==x;
}
I pushup(R x)
{prd[x]=val[x];if(c[x][0]) prd[x]=mul(prd[c[x][0]],prd[x]);if(c[x][1]) prd[x]=mul(prd[x],prd[c[x][1]]);
}
I rotate(R x)
{R y=f[x],z=f[y],d=chk(x)^1,w=c[x][d];if(nroot(y)) c[z][chk(y)]=x;c[x][d]=y; c[y][d^1]=w;if(w) f[w]=y;f[x]=z; f[y]=x;pushup(y); pushup(x);return; 
}
I splay(R x)
{R y=x,z=0;while(nroot(x)){y=f[x];z=f[y];if(nroot(y))rotate((c[z][0]==y)^(c[y][0]==x)?y:x);rotate(x);  } 
}
I access(R x)
{for(int y=0;x;x=f[y=x]){splay(x);if(c[x][1]){val[x].data[0][0]+=max(prd[c[x][1]].data[0][0],prd[c[x][1]].data[1][0]); //因为y变成了实儿子,那么我们就要加上原来实儿子对于g(val)的贡献,减去y对g(val)的贡献val[x].data[1][0]+=prd[c[x][1]].data[0][0];}if(y){val[x].data[0][0]-=max(prd[y].data[0][0],prd[y].data[1][0]);val[x].data[1][0]-=prd[y].data[0][0];}val[x].data[0][1]=val[x].data[0][0];rc=y;pushup(x);}
}
I dfs(R x,R fa)
{dp[x][1]=a[x];  //用最开始的dp值来初始化f(pre)和g(val)for(int i=head[x];i;i=node[i].next){int d=node[i].t;if(d==fa) continue;dfs(d,x);f[d]=x; dp[x][0]+=max(dp[d][0],dp[d][1]); dp[x][1]+=dp[d][0];} val[x].data[0][0]=val[x].data[0][1]=dp[x][0];val[x].data[1][0]=dp[x][1];prd[x]=val[x];
}
I modify(R x,R y)
{access(x); splay(x);val[x].data[1][0]-=a[x]-y;pushup(x);a[x]=y;
}
int main()
{
//  freopen(".in","r",stdin);
//  freopen(".out","w",stdout); tot=0;scanf("%d %d",&n,&m);for(int i=1;i<=n;++i) scanf("%d",&a[i]);for(int i=1;i<=n-1;++i) {int x,y;scanf("%d %d",&x,&y);add(x,y); add(y,x);}dfs(1,0);for(int i=1;i<=m;++i){int x,y;scanf("%d %d",&x,&y);   modify(x,y);splay(1);  //询问前要将1旋转到根,维护修改后的信息printf("%d\n",max(prd[1].data[0][0],prd[1].data[1][0]));}return 0;
} 

转载于:https://www.cnblogs.com/Call-me-zhz/p/11366427.html


http://chatgpt.dhexx.cn/article/2UYo9auc.shtml

相关文章

移动端适配dpr

1. 移动端适配的代码&#xff08;设计稿iPhone6&#xff09;如下&#xff1a; (function (doc,win) {// seMetaTagScale(doc, win)var fn function () { var deviceWidth doc.documentElement.clientWidth; // css逻辑像素&#xff0c;不是物理像素if (deviceWidth > 82…

移动端布局(一)dp、dip、PPI、dpr、图片模糊

注: 此篇文章引用多篇文章&#xff0c;在文章的结尾处有注明文章的来源 高清屏 即高清屏,把更多的像素压缩至一块屏幕里&#xff0c;从而达到更高分辨率显示的细腻程度&#xff0c;使人眼无法分辨出单个的像素。 物理像素(dp) 物理像素&#xff0c;设备的硬件像素&#xff…

不同设备屏幕尺寸和DPR适配

为什么需要适配 目前市面上设备屏幕属性十分多样化&#xff08;宽度和DPR并不一致&#xff09;&#xff0c;而作为设计和前端开发&#xff0c;无法为每个尺寸的设备单独设计一套UI并将其转为前端代码&#xff0c;这不现实。所以我们需要一套方案来将一套设计稿完美呈现在不同尺…

DPR-ERR-2109

问题&#xff08;摘要&#xff09; [Simplified Chinese] 该技术文档说明了如何解决在安装和配置IBM Rational Common Reporting服务器时可能发生的错误:"DPR-ERR-2109 The dispatcher cannot service the request at this time. The dispatcher is still initializing. …

DPR和REALM论文笔记

DPR(2020 EMNLP) 该论文的模型主要是一个双塔结构如下所示&#xff1a; 整个模型的训练数据D包含m个例子&#xff0c;其中每个例子由一个问题 q i q_i qi​、一个相关段落 p i p_i^ pi​、n个不相关段落 p i , 1 − , ⋯ , p i , n − p_{i,1}^-,\cdots,p_{i,n}^- pi,1−​,⋯…

dpr单位

1px dpr^2 * dp 这个是不是有问题&#xff1f; 结尾的总结&#xff1a; 1px dpr^2 * dp 这个是不是有问题&#xff1f; 以下这个等式不成立吧: 320*568 px 2^2 * 1136*640 1px dpr ^2 * dp 是平面上的像素换算&#xff0c;但实际开发当中使用更多的是长度上的换算&#x…

图文并茂带你弄懂物理分辨率、分辨率、物理像素、逻辑像素、dpr、ppi

目录 物理分辨率和分辨率 什么是物理像素 什么是CSS像素 什么是设备像素比 什么是标清屏和高清屏 缩放 什么是PPI&#xff08;DPI&#xff09; 物理分辨率和分辨率 首先得知道物理分辨率和分辨率是2个概念&#xff0c;可别混淆。 物理分辨率&#xff08;标准分辨率&am…

DPSR

testsets/real_imgs/LR 图片chip.pngchip_kernel.pngcolour.pngcolour_kernel.pngfrog.png尺寸109x557x7668x45599x99500x375 testsets/real_imgs/x4_dpsr 图片chip.pngchip_x2.pngchip_x3.pngchip_x4.png尺寸109x55218x110327x165436x220 testsets/Set5/GT 图片&#xff1a;…

说说设备像素、css像素、设备独立像素、dpr、ppi 之间的区别?

一、背景 在css中我们通常使用px作为单位&#xff0c;在PC浏览器中css的1个像素都是对应着电脑屏幕的1个物理像素 这会造成一种错觉&#xff0c;我们会认为css中的像素就是设备的物理像素 但实际情况却并非如此&#xff0c;css中的像素只是一个抽象的单位&#xff0c;在不同…

15-移动端布局基础——DPI、PPI、物理像素、DPR、viewportcss像素、DPR

文章目录 1. DPI 和 PPI 是什么&#xff1f;一、物理像素和css像素三、设备像素比DPR四、viewport五、viewport三理论&#xff1a;布局视口、视觉视口、理想视口五、利用meta标签对viewport进行控制 1. DPI 和 PPI 是什么&#xff1f; DPI ---- 最初用于衡量打印物上每英寸的点…

【CSS】聊一聊CSS像素、设备像素、设备独立像素、dpr、ppi 之间的区别

前言 大家好&#xff0c;我是HoMeTown&#xff0c;顺着计量单位&#xff0c;想继续聊一下CSS像素、设备像素、设备独立像素、dpr、ppi 之间的区别。 众所周知&#xff0c;在CSS中我们通常是使用px作为单位的场景多一点&#xff0c;在PC端&#xff0c;1个像素恰好对应电脑屏幕…

移动web开发之像素和DPR详解

前话&#xff1a;   像素在web开发中几乎天天用到&#xff0c;但到底什么是像素&#xff0c;移动端和桌面端的像素有区别吗&#xff0c;缩放对像素有影响吗&#xff0c;视网膜屏幕和像素有什么关系&#xff1f;关于这些问题&#xff0c;可能就不清楚了。本文将介绍关于像素的…

DPR

Dense Passage Retrieval for Open-Domain Question Answering https://github.com/facebookresearch/DPR摘要 开放域问题回答依赖于有效的段落检索来选择候选上下文&#xff0c;其中传统的稀疏向量空间模型&#xff0c;如TF-IDF或BM25&#xff0c;是事实上的方法。作者表明检…

如何理解dpr

首先如何在设备上实现1px边框&#xff1a; 物理像素: 在视网膜屏下面, 显示的实际的像素颗粒&#xff0c;iphone6分辨率7501334px 逻辑像素: 可以认为成就是设备的宽度,css设置的像素&#xff0c;iphone6逻辑像素7501334px dpr 物理像素(设备像素) /逻辑像素(设备独立像素) 所…

基于C99标准的C语言coding技巧

文章目录 Union宏定义数组和柔性数组其它 Union 共用体中有int型和char[10]这两个成员&#xff0c;代码如下&#xff1a; #include <stdio.h> union st { int x; char c[10]; }s;int main(void) { s.x50; s.c"abcdef"; printf("%s",s.c); return 0…

C语言的三套标准:C89、C99和C11

我们今天使用的 Windows、Linux、Mac OS 等操作系统都是由一种叫做 Unix 的系统演化而来。Unix 作为80年代主流的操作系统&#xff0c;是整个软件工业的基础&#xff0c;是现代操作系统的开山鼻祖&#xff0c;C语言就是为 Unix 而生的。 Unix 和C语言的开发者是同一人&#xf…

ANSI C、C89、C99和C51的区别

ANSI C、C89、C99和C51的区别 什么是ANSI C、ISO C、C89、C90标准&#xff1f; 随着C语言使用得越来越广泛&#xff0c;出现了许多新问题&#xff0c;人们日益强烈地要求对C语言进行标准化。1983年&#xff0c;美国国家标准协会&#xff08;ANSI&#xff09;组成了一个委员会…

VS不支持C99标准变长数组的概念

#《VS不支持C99标准变长数组的概念》 文章目录 1.visual studio2022**2.GCC 1.为什么会报错&#xff0c;而gcc编译器不会&#xff1f; *案例 2.vs和gcc的区别 3.总结 案例 1.在第一张图中我们可以看到inta[n]这个地方在报错而且提示表达式的计算结果不是常数&#xff0c;意思就…

c89与c99区别

注&#xff1a; GCC支持C99, 通过 --stdc99 命令行参数开启&#xff0c;如&#xff1a;    代码: gcc --stdc99 test.c --------------------------------------------------------------------------------------------------      1、增加restrict指针   C99中增加了…

C89、C99和C11标准之间的差异

收集了大部分差异特性&#xff0c;不断完善和补充&#xff0c;有遗漏的地方欢迎留言补正。 一、C99针对C89的改变 1.增加了restrict指针 通过restrict修饰指针&#xff0c;可以确保两个指针不能指向同样的内存空间。 如memcpy函数在C99标准下的定义为 void *memcpy(void *rest…