首页 > 其他分享 >DDP

DDP

时间:2024-07-21 21:07:49浏览次数:12  
标签:matrix val int DDP son maxn bmatrix

线段树+树剖/\(lct\)维护广义矩阵乘法

从例题开始讲

P4719

如果不带修改,那么就好做了

\(f_{i, 1 / 0}\) 表示 \(i\) 节点选或不选的最大权

容易得到转移

\[ f_{i, 0} = \sum_{son} max(f_{son, 0}, f_{son, 1}) \]

\[ f_{i, 1} = w_i+\sum_{son} f_{son, 0} \]

但是现在带修。

你会发现,一次修改只会影响一条链上的值,但不幸的是暴力修改仍是不可接受的

有什么方法可以快速处理树链?树剖,(LCT)

现在的问题是如何快速维护一条树链的 \(DP\) 值

我们先引入 广义矩阵乘法

image

那么这根我们的 \(DP\) 有什么关系呢?

我们尝试将 \(DP\) 写成矩阵的形式

为了保证复杂度,我们定义 \(g_{i, 0/1}\) 表示只考虑 \(i\) 的轻儿子, \(i\) 选或不选的最大值

那么有 (\(son\) 为重儿子)

\[ f_{i, 0} = g_{i, 0} + max(f_{son, 1}, f_{son, 0}) \]

\[ f_{i, 1} = g_{i,1} + f_{son, 0} \]

把他写成广义矩阵

\[ \begin{bmatrix} g_{i,0} & g_{i,0}\\ g_{i,1} & -\infty \end{bmatrix}\times \begin{bmatrix} f_{son,0}\\f_{son,1} \end{bmatrix}= \begin{bmatrix} f_{i,0}\\f_{i,1} \end{bmatrix} \]

使用树剖+线段树维护区间转移矩阵,就能快速转移一条重链,而修改只需修改他的 \(g_{i, 1}\)和向上的一条链

image

code
#include<cstring>
#include<algorithm>
#include<queue>
#include<iostream>
#include<cmath>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
int read(){
	int x = 0; bool f = 0;char c = getchar();
	while(!isdigit(c)){f = c == '-';c = getchar();}
	do{x = x * 10 + (c ^ 48); c = getchar();}while(isdigit(c));
	return f ? -x : x;
}
const int maxn = 100005;

struct matrix{
	int a[2][2];
	matrix(){memset(a, -0x3f, sizeof(a));}
	matrix operator *(const matrix b){
		matrix ans;
		for(int i = 0; i < 2; ++i)
			for(int k = 0; k < 2; ++k)
				for(int j = 0; j < 2; ++j)
					ans.a[i][j] = max(ans.a[i][j], a[i][k] + b.a[k][j]);
		return ans;
	}
};
int n, m, a[maxn];
int head[maxn], tot;
struct edge{int to, net;}e[maxn << 1 | 1];
void add(int u, int v){
	e[++tot].net = head[u];
	head[u] = tot;
	e[tot].to = v;
}
int son[maxn], fa[maxn], top[maxn], ed[maxn], size[maxn], dep[maxn];
matrix val[maxn];
int f[maxn][2];

void dfs1(int x){
	size[x] = 1;
	for(int i = head[x]; i; i = e[i].net){
		int v = e[i].to;
		if(v == fa[x])continue;
		dep[v] = dep[x] + 1, fa[v] = x;
		dfs1(v);
		size[x] += size[v];
		son[x] = size[son[x]] > size[v] ? son[x] : v;
		f[x][0] += max(f[v][0], f[v][1]);
		f[x][1] += f[v][0];
	}
	f[x][1] += a[x];
}
int tim, id[maxn], dfn[maxn];

void dfs2(int x, int tp){
	dfn[x] = ++tim; id[tim] = x; top[x] = tp;
	ed[tp] = tim;
	if(son[x])dfs2(son[x], tp);
	val[x].a[1][0] = a[x];
	val[x].a[0][1] = 0;
	for(int i = head[x]; i; i = e[i].net){
		int v = e[i].to;
		if(v == son[x] || v == fa[x])continue;
		dfs2(v, v);
		val[x].a[0][1] += max(f[v][1], f[v][0]);
		val[x].a[1][0] += f[v][0];
	}
	val[x].a[0][0] = val[x].a[0][1];
}

struct seg{
	matrix t[maxn << 2 | 1];
	void push_up(int x){t[x] = t[x << 1] * t[x << 1 | 1];}
	void built(int x, int l, int r){
		if(l == r){t[x] = val[id[l]]; return;}
		int mid = (l + r) >> 1;
		built(x << 1, l, mid);
		built(x << 1 | 1, mid + 1, r);
		push_up(x);
	}
	matrix query(int x, int l, int r, int L, int R){
		if(L <= l && r <= R)return t[x];
		int mid = (l + r) >> 1;
		if(R <= mid)return query(x << 1, l, mid, L, R);
		if(L > mid)return query(x << 1 | 1, mid + 1, r, L, R);
		return query(x << 1, l, mid, L, R) * query(x << 1 | 1, mid + 1, r, L, R);
	}
	void modify(int x, int l, int r, int pos){
		if(l == r){
			t[x] = val[id[pos]];
			return;
		}
		int mid = (l + r) >> 1;
		if(pos <= mid)modify(x << 1, l, mid, pos);
		else modify(x << 1 | 1, mid + 1, r, pos);
		push_up(x);
	}
}t;

void upd(int x, int y){
	val[x].a[1][0] += y - a[x]; a[x] = y;
	matrix las, now;
	while(x){
		las = t.query(1, 1, n, dfn[top[x]], ed[top[x]]);
		t.modify(1, 1, n, dfn[x]);
		now = t.query(1, 1, n, dfn[top[x]], ed[top[x]]);
		x = fa[top[x]];
		val[x].a[0][0] += max(now.a[0][0], now.a[1][0]) - max(las.a[0][0], las.a[1][0]);
		val[x].a[0][1] = val[x].a[0][0];
		val[x].a[1][0] += now.a[0][0] - las.a[0][0];
	}
}

int main(){
	n = read(), m = read();
	for(int i = 1; i <= n; ++i)a[i] = read();
	for(int i = 1; i < n; ++i){
		int u = read(), v = read();
		add(u, v); add(v, u);
	}
	dfs1(1); dfs2(1, 1);
	t.built(1, 1, n);
	for(int i = 1; i <= m; ++i){
		int x = read(), y = read();
		upd(x, y);
		matrix ans = t.query(1, 1, n, dfn[1], ed[1]);
		printf("%d\n",max(ans.a[0][0], ans.a[1][0]));
	}
	return 0;
}

最小权覆盖集 \(=\) 全集 \(-\) 最大权独立集

然后嘞?怎么处理制选和强制不选?

现在思考一下如何转化为上一个问题。

强制不选设为 \(-inf\) 强制选设为 \(inf\) 并给全集加上 \(inf\)

然后就跟上个题一样了。就是常数大了点。

这个题其实可以用树上倍增的做法,其实也差不多。

我们的\(CSP\)题。。。

部分分看着拿。

\(k = 1\)直接剖

\(k = 2\) 不会到链外(图),于是如果把链抽出来就是

\(f_{i} = w_i + min(f_{i - 1}, f_{i - 2})\)

不妨设 \(f_{i, 0 / 1 / 2}\) 表示走到距离点 \(i\) 距离为 \(0 / 1 / 2\) 的权值

上面的式子可以简单改写一下。

\(k = 3\)

一定只会跳到邻接点(图)

预处理 \(g_i\) 表示 \(i\) 邻接点最小权值

可以写出转移

\[ f_{i, 0} = min(f_{las, 0}, f_{las, 1}, f_{las, 2}) + w_i \]

\[ f_{i, 1} = min(f_{las, 0}, f_{las, 1} + g_i) \]

\[ f_{i, 2} = f_{las, 1} \]

以上转化成广义矩阵乘法形式可以使用树剖等手法维护。

标签:matrix,val,int,DDP,son,maxn,bmatrix
From: https://www.cnblogs.com/Chencgy/p/18314293

相关文章

  • 使用Pytorch中从头实现去噪扩散概率模型(DDPM)
    扩散模型通常是一种生成式深度学习模型,它通过学习去噪过程来创建数据。扩散模型有许多变体,其中最流行的是条件文本模型,能够根据提示生成特定的图像。某些扩散模型(如Control-Net)甚至能将图像与某些艺术风格融合。在本文中,我们将构建基础的无条件扩散模型,即去噪扩散概率模型(DDPM)。......
  • 从DDPM到DDIM
    从DDPM到DDIM(一)现在网络上关于DDPM和DDIM的讲解有很多,但无论什么样的讲解,都不如自己推到一边来的痛快。笔者希望就这篇文章,从头到尾对扩散模型做一次完整的推导。DDPM是一个双向马尔可夫模型,其分为扩散过程和采样过程。扩散过程是对于图片不断加噪的过程,每一步添加少量的高......
  • 生成扩散模型漫谈(四):DDIM = 高观点DDPM
    相信很多读者都听说过甚至读过克莱因的《高观点下的初等数学》这套书,顾名思义,这是在学到了更深入、更完备的数学知识后,从更高的视角重新审视过往学过的初等数学,以得到更全面的认知,甚至达到温故而知新的效果。类似的书籍还有很多,比如《重温微积分》、《复分析:可视化方法》等。回到......
  • 生成扩散模型漫谈(一):DDPM = 拆楼 + 建楼
    说到生成模型,VAE、GAN可谓是“如雷贯耳”,本站也有过多次分享。此外,还有一些比较小众的选择,如flow模型、VQ-VAE等,也颇有人气,尤其是VQ-VAE及其变体VQ-GAN,近期已经逐渐发展到“图像的Tokenizer”的地位,用来直接调用NLP的各种预训练方法。除了这些之外,还有一个本来更小众的选择——扩......
  • 生成扩散模型漫谈(二):DDPM = 自回归式VAE
    在文章《生成扩散模型漫谈(一):DDPM=拆楼+建楼》中,我们为生成扩散模型DDPM构建了“拆楼-建楼”的通俗类比,并且借助该类比完整地推导了生成扩散模型DDPM的理论形式。在该文章中,我们还指出DDPM本质上已经不是传统的扩散模型了,它更多的是一个变分自编码器VAE,实际上DDPM的原论文中也......
  • 生成扩散模型漫谈(三):DDPM = 贝叶斯 + 去噪
    到目前为止,笔者给出了生成扩散模型DDPM的两种推导,分别是《生成扩散模型漫谈(一):DDPM=拆楼+建楼》中的通俗类比方案和《生成扩散模型漫谈(二):DDPM=自回归式VAE》中的变分自编码器方案。两种方案可谓各有特点,前者更为直白易懂,但无法做更多的理论延伸和定量理解,后者理论分析上更加......
  • 生成扩散模型漫谈(一):DDPM = 拆楼 + 建楼
    说到生成模型,VAE、GAN可谓是“如雷贯耳”,本站也有过多次分享。此外,还有一些比较小众的选择,如flow模型、VQ-VAE等,也颇有人气,尤其是VQ-VAE及其变体VQ-GAN,近期已经逐渐发展到“图像的Tokenizer”的地位,用来直接调用NLP的各种预训练方法。除了这些之外,还有一个本来更小众的选择——扩......
  • DDP:微软提出动态detection head选择,适配计算资源有限场景 | CVPR 2022
    DPP能够对目标检测proposal进行非统一处理,根据proposal选择不同复杂度的算子,加速整体推理过程。从实验结果来看,效果非常不错来源:晓飞的算法工程笔记公众号论文:ShouldAllProposalsbeTreatedEquallyinObjectDetection?论文地址:https://arxiv.org/abs/2207.03520......
  • DDPM生成人脸代码
    基于DDPM介绍的理论,简单实现DDPM生成人脸,代码如下:utils.pyimportosfromtorch.utils.dataimportDatasetfromtorchvision.transformsimporttransformsimportglobimportcv2classMyDataset(Dataset):def__init__(self,img_path,device):super(My......
  • DDPM扩散概率模型数学原理推导
    DDPM正向过程定义前向过程被定义为一个从初始数据x0x_0x0​开始的马尔可夫链。而他的目标是要由......