数据结构选讲 (更新中)

参考 smWCDay7 数据结构选讲2 by yyc

可能会补充的:

  • AT_cf17_final_j TreeMSTF2 Boruvka算法

目录

  • AT_cf17_final_j Tree MST
  • P5280 [ZJOI2019] 线段树

AT_cf17_final_j Tree MST

link
题意
给定一棵 n n n 个点的树,点有点权 w i w_i wi,边有边权。建立一张完全图 G G G,节点 u , v u, v u,v 之间的边长为 w u + w v + d i s ( u , v ) w_u + w_v + dis(u, v) wu+wv+dis(u,v) 。求 G G G M S T MST MST (最小生成树)的边权和。

  • n ≤ 2 × 1 0 5 , 1 ≤ w i ≤ 1 0 9 n \le 2 \times 10^5 ,1 \le w_i \le 10^9 n2×1051wi109

思路
前置指示:点分治

引理:边 e e e 在边集 E E E 的最小生成树中,则对于任意 E 0 ⊆ E E_0 ⊆ E E0E,e 也在边集 E 0 E_0 E0 的最小生成树中。
证明:考虑 kruskal
推论:将边分为若干组,分别求最小生成树,再合并求最小生成树,结果正确。

题目是说建立一张完全图然后求其的 M S T MST MST ,但是这样的边是 n 2 n^2 n2 级别的,考虑去掉一些多余的边,只保留有用的边。所以可以将完全图 G G G 分成很多个边集,分别求 M S T MST MST (不必强制联通),然后保留有用边,最后再综合求 M S T MST MST 就是答案了。
考虑 点分治,以重心为根,将树分成几个子树,那么就只用处理跨越重心的边即可。
d i s i dis_i disi 表示 点 i i i 到重心的距离,跨越重心的边 ( u , v ) (u,v) (u,v),边权是 w u + d i s u + w v + d i s v w_u + dis_u + w_v + dis_v wu+disu+wv+disv 。由于每个点 i i i 都要贡献至少一次 w i + d i s i w_i+dis_i wi+disi,另外一边肯定选最小的 w j + d i s j w_j+dis_j wj+disj ,所以我们只需要选择 w i + d i s i w_i + dis_i wi+disi 最小的点,让它和所有其他点连边,该菊花图就是最小生成树。(在同一棵子树内连了边也不影响结果,因为它们的边权比真实值要大 d i s u + d i s v > d i s u , v dis_u + dis_v \gt dis_{u,v} disu+disv>disu,v )。这样边的数量就减到了 n l o g n nlogn nlogn,总时间复杂度为 O ( n l o g 2 n ) O(nlog^2n) O(nlog2n)

好像还有一种方法,要用到 Boruvka算法 ,后续可能会学……

代码

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=2e5+5;

int idx,head[maxn];
struct EDGE{ int v,next; ll w; }e[maxn*2];
void Insert(int u,int v,ll w){
	e[++idx]={v,head[u],w};
	head[u]=idx;
}

int siz[maxn],mxson[maxn],pot[maxn],tn;
bool vis[maxn];
void Dfs(int x,int fa){
	pot[++tn]=x,siz[x]=1,mxson[x]=0;
	for(int i=head[x];i;i=e[i].next){
		int v=e[i].v;
		if(!vis[v]&&v!=fa){
			Dfs(v,x);
			siz[x]+=siz[v];
			mxson[x]=max(mxson[x],siz[v]);
		}
	}
}

int Get_root(int x){
	tn=0,Dfs(x,0);
	int root=0;
	for(int i=1;i<=tn;i++){
		mxson[pot[i]]=max(mxson[pot[i]],tn-siz[pot[i]]);
		if(!root||mxson[root]>mxson[pot[i]]) root=pot[i]; 
	}
	return root;
}

int id;
ll a[maxn],dis[maxn];
void Dfs2(int x,int fa){
	for(int i=head[x];i;i=e[i].next){
		int v=e[i].v;
		if(!vis[v]&&v!=fa){
			dis[v]=dis[x]+e[i].w;
			Dfs2(v,x);
		}
	}
	if(!id||a[x]+dis[x]<a[id]+dis[id]) id=x;
}

int cnt;
struct EDGE2{ int u,v; ll w; }te[maxn*20];
void Solve(int rt){
	dis[rt]=0,id=0,Dfs2(rt,0);
	for(int i=1;i<=tn;i++)
		te[++cnt]={id,pot[i],a[id]+dis[id]+a[pot[i]]+dis[pot[i]]};
	vis[rt]=1;
	for(int i=head[rt];i;i=e[i].next){
		int v=e[i].v;
		if(!vis[v]) Solve(Get_root(v));
	}
}

int fa[maxn];
int Find_fa(int x){ return fa[x]==x?x:fa[x]=Find_fa(fa[x]); }

int main(){
	int n; cin>>n;
	for(int i=1;i<=n;i++)
		cin>>a[i];
	for(int i=1;i<n;i++){
		int x,y,z; cin>>x>>y>>z;
		Insert(x,y,z),Insert(y,x,z);
	}
	Solve(Get_root(1));
	sort(te+1,te+cnt+1,[](EDGE2 a,EDGE2 b){ return a.w<b.w; });
	for(int i=1;i<=n;i++)
		fa[i]=i;
	ll ans=0;
	for(int i=1;i<=cnt;i++){
		int fx=Find_fa(te[i].u),fy=Find_fa(te[i].v);
		if(fx!=fy) fa[fy]=fx,ans+=te[i].w;
	}
	cout<<ans;
	return 0;
}

P5280 [ZJOI2019] 线段树

link
题意
维护线段树集合,初始时,集合中只有一棵 [ 1 , n ] [1, n] [1,n] 的空线段树。支持下列操作:

  • 将每棵线段树复制两份,其中一份执行区间覆盖。
  • 查询目前所有线段树中,有标记的节点个数。
  • n , m ≤ 1 0 5 n, m \le 10^5 n,m105

思路
看到题目,可以想到:线段树的个数是指数级别的,不可能单独地去维护每一棵线段树,但每棵线段树都是相同的,思考是否可以去用一棵线段树来维护,每次修改在上一次的基础上进行转移。 又发现一次修改中,不同的点的转移是不同的。
那就观察点的修改,总共可以分成五类:
picture

  • 白色:在 Modify 操作中,被半覆盖的点;
  • 深灰色:在 Modify 操作中,被全覆盖的点,并且能被遍历到;
  • 橙色:在 Modify 操作中,未被覆盖的点,并且可能可以得到 pushdown 来的标记;
  • 浅灰色:在 Modify 操作中,被全覆盖的点,并且不能被遍历到(深灰色点的儿子);
  • 黄色:在 Modify 操作中,未被覆盖的点,并且不可能得到 pushdown 来的标记(橙色点的儿子);

设个 D P DP DP 观察五种点的转移:记 f i , u f_{i,u} fi,u 表示到第 i i iModify 操作时, 在 2 i 2^i 2i 棵树中,点 u u u 被打了标记的个数;  g i , u g_{i,u} gi,u 表示到第 i i iModify 操作时, 在 2 i 2^i 2i 棵树中,有多少棵树满足根到结点 u u u 的路径上的点至少有一个标记。
转移如下:

  • 白色: f i , u = f i − 1 , u f_{i,u} = f_{i−1,u} fi,u=fi1,u g i , u = g i − 1 , u g_{i,u} = g_{i−1,u} gi,u=gi1,u
  • 深灰色: f i , u = f i − 1 , u + 2 i − 1 f_{i,u} = f_{i−1,u} + 2^{i-1} fi,u=fi1,u+2i1 g i , u = g i − 1 , u + 2 i − 1 g_{i,u} = g_{i−1,u} + 2^{i-1} gi,u=gi1,u+2i1
  • 橙色: f i , u = f i − 1 , u + g i − 1 , u f_{i,u} = f_{i−1,u} + g_{i-1,u} fi,u=fi1,u+gi1,u g i , u = 2 × g i − 1 , u g_{i,u} = 2 \times g_{i−1,u} gi,u=2×gi1,u
  • 浅灰色: f i , u = 2 × f i − 1 , u f_{i,u} = 2 \times f_{i−1,u} fi,u=2×fi1,u g i , u = g i − 1 , u + 2 i − 1 g_{i,u} = g_{i−1,u} + 2^{i-1} gi,u=gi1,u+2i1
  • 黄色: f i , u = 2 × f i − 1 , u f_{i,u} = 2 \times f_{i−1,u} fi,u=2×fi1,u g i , u = 2 × g i − 1 , u g_{i,u} = 2 \times g_{i−1,u} gi,u=2×gi1,u

每次修改暴力转移每个点是不可能的。但每次的白色,深灰色,橙色只有 O ( l o g n ) O(logn) O(logn) 个,可以暴力;浅灰色和黄色有 O ( n ) O(n) O(n) 个,可以用懒标记维护。还要维护 s u m u sum_u sumu 表示 u u u 子树中 f u f_u fu 的总和, s u m 1 sum_1 sum1 就是答案。
维护转移时有点细节(懒标记),注意多 p u s h d o w n pushdown pushdown 标记。

代码

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=1e5+5,mod=998244353;

struct TREE{ ll f,g,tagf,tagg,tagg2,sum; }tree[maxn*4];
void Build(int rt,int l,int r){
	tree[rt].tagf=tree[rt].tagg2=1;
	if(l==r) return;
	int mid=(l+r)>>1;
	Build(rt*2,l,mid),Build(rt*2+1,mid+1,r);
}

void F_mul(int rt,ll k){ (tree[rt].f*=k)%=mod,(tree[rt].tagf*=k)%=mod,(tree[rt].sum*=k)%=mod; }
void G_add(int rt,ll k){ (tree[rt].g+=k)%=mod,(tree[rt].tagg+=k)%=mod; }
void G_mul(int rt,ll k){ (tree[rt].g*=k)%=mod,(tree[rt].tagg2*=k)%=mod,(tree[rt].tagg*=k)%=mod; }
void Pushdown(int rt){
	int ls=rt*2,rs=ls+1;
	if(tree[rt].tagf!=1) F_mul(ls,tree[rt].tagf),F_mul(rs,tree[rt].tagf),tree[rt].tagf=1;
	if(tree[rt].tagg2!=1) G_mul(ls,tree[rt].tagg2),G_mul(rs,tree[rt].tagg2),tree[rt].tagg2=1;
	if(tree[rt].tagg) G_add(ls,tree[rt].tagg),G_add(rs,tree[rt].tagg),tree[rt].tagg=0;
}
void Pushup(int rt){ tree[rt].sum=(tree[rt*2].sum+tree[rt*2+1].sum+tree[rt].f)%mod; }

void Modify(int rt,int l,int r,int x,int y,ll z){//white, deep_grey, light_grey
	if(x<=l&&r<=y){//deep_grey
		(tree[rt].f+=z)%=mod,(tree[rt].g+=z)%=mod;
		F_mul(rt*2,2),G_add(rt*2,z); F_mul(rt*2+1,2),G_add(rt*2+1,z);//light_grey
		Pushup(rt);
		return;
	}
	Pushdown(rt);
	int mid=(l+r)>>1;
	if(x<=mid) Modify(rt*2,l,mid,x,y,z);
	if(y>mid) Modify(rt*2+1,mid+1,r,x,y,z);
	Pushup(rt);
}

void Modify2(int rt,int l,int r,int x,int y){//orange, yello
	if(x<=l&&r<=y){//orange
		(tree[rt].f+=tree[rt].g)%=mod,(tree[rt].g*=2)%=mod;
		F_mul(rt*2,2),G_mul(rt*2,2); F_mul(rt*2+1,2),G_mul(rt*2+1,2);//yellow
		Pushup(rt);
		return;
	}
	Pushdown(rt);
	int mid=(l+r)>>1;
	if(x<=mid) Modify2(rt*2,l,mid,x,y);
	if(y>mid) Modify2(rt*2+1,mid+1,r,x,y);
	Pushup(rt);
}

ll pw[maxn];
int main(){
	int n,m; cin>>n>>m;
	pw[0]=1;
	for(int i=1;i<=m;i++)
		pw[i]=pw[i-1]*2%mod;
	Build(1,1,n);
	int cnt=0;
	while(m--){
		int opt; cin>>opt;
		if(opt==1){
			int x,y; cin>>x>>y; cnt++;
			Modify(1,1,n,x,y,pw[cnt-1]);
			if(x>1) Modify2(1,1,n,1,x-1);
			if(y<n) Modify2(1,1,n,y+1,n);
		}
		else cout<<tree[1].sum<<"\n";
	}
	return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/962379.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【01】共识机制

BTF共识 拜占庭将军问题 拜占庭将军问题是一个共识问题 起源 Leslie Lamport在论文《The Byzantine Generals Problem》提出拜占庭将军问题。 核心描述 军中可能有叛徒&#xff0c;却要保证进攻一致&#xff0c;由此引申到计算领域&#xff0c;发展成了一种容错理论。随着…

春晚舞台上的人形机器人:科技与文化的奇妙融合

文章目录 人形机器人Unitree H1的“硬核”实力传统文化与现代科技的创新融合网友热议与文化共鸣未来展望&#xff1a;科技与文化的更多可能结语 2025 年央视春晚的舞台&#xff0c;无疑是全球华人目光聚焦的焦点。就在这个盛大的舞台上&#xff0c;一场名为《秧BOT》的创意融合…

.NET Core缓存

目录 缓存的概念 客户端响应缓存 cache-control 服务器端响应缓存 内存缓存&#xff08;In-memory cache&#xff09; 用法 GetOrCreateAsync 缓存过期时间策略 缓存的过期时间 解决方法&#xff1a; 两种过期时间策略&#xff1a; 绝对过期时间 滑动过期时间 两…

如何从客观角度批判性阅读分析博客

此文仅以个人博客为例&#xff0c;大量阅读朋友反馈给我的交流让我得知他们所理解我的博客所表达的意思并非我所想表达的&#xff0c;差异或大或小&#xff0c;因人而异。 观点与事实 只有从客观角度反复批判性阅读和分析&#xff0c;才能逐渐清晰观点和事实。 观点不等于事实…

【力扣】49.字母异位词分组

AC截图 题目 思路 由于互为字母异位词的两个字符串包含的字母相同&#xff0c;因此对两个字符串分别进行排序之后得到的字符串一定是相同的&#xff0c;故可以将排序之后的字符串作为哈希表的键。 可以遍历strs&#xff0c;将其中每一个str排序&#xff0c;然后用unodered_ma…

【4Day创客实践入门教程】Day4 迈向高手之路——进一步学习!

Day4 迈向高手之路——进一步学习&#xff01; 目录 Day4 迈向高手之路——进一步学习&#xff01;更多的开发板外壳制作 Day0 创想启程——课程与项目预览Day1 工具箱构建——开发环境的构建Day2 探秘微控制器——单片机与MicroPython初步Day3 实战演练——桌面迷你番茄钟Day4…

什么是线性化PDF?

线性化PDF是一种特殊的PDF文件组织方式。 总体而言&#xff0c;PDF是一种极为优雅且设计精良的格式。PDF由大量PDF对象构成&#xff0c;这些对象用于创建页面。相关信息存储在一棵二叉树中&#xff0c;该二叉树同时记录文件中每个对象的位置。因此&#xff0c;打开文件时只需加…

向下调整算法(详解)c++

算法流程&#xff1a; 与⽗结点的权值作⽐较&#xff0c;如果⽐它⼤&#xff0c;就与⽗亲交换&#xff1b; 交换完之后&#xff0c;重复 1 操作&#xff0c;直到⽐⽗亲⼩&#xff0c;或者换到根节点的位置 大家可能会有点疑惑&#xff0c;这个是大根堆&#xff0c;22是怎么跑到…

unity学习25:用 transform 进行旋转和移动,简单的太阳地球月亮模型,以及父子级关系

目录 备注内容 1游戏物体的父子级关系 1.1 父子物体 1.2 坐标关系 1.3 父子物体实际是用 每个gameobject的tranform来关联的 2 获取gameObject的静态数据 2.1 具体命令 2.2 具体代码 2.3 输出结果 3 获取gameObject 的方向 3.1 游戏里默认的3个方向 3.2 获取方向代…

C基础算法与实现

前言 通过业务侧输入需求,使用代码完成。 1.偶数立方和 编写函数求1~100中奇数的平方与偶数的立方的和 1.1代码实现结果 1.2源码示例 #include <stdio.h>// 计算1到100中奇数的平方与偶数的立方的和 int calculateSum() {int sum 0;// 遍历1到100之间的所有数字for (…

基于SSM实现的乡村振兴文化平台系统功能实现十八

一、前言介绍&#xff1a; 1.1 项目摘要 农耕文明是广大群众在几千年的农业生产生活中智慧的结晶&#xff0c;不仅是乡土文化的核心和精髓&#xff0c;还是中华文明的起源和基因。因此&#xff0c;传承和发扬优秀乡村文化&#xff0c;是传承农耕文明的必然要求。 文化振兴是乡…

如何让一个用户具备创建审批流程的权限

最近碰到一个问题&#xff0c;两个sandbox&#xff0c;照理用户的权限应该是一样的&#xff0c;结果开发环境里面我可以左右的做各种管理工作&#xff0c;但是使用change set上传后&#xff0c;另一个环境的同一个用户&#xff0c;没有相对于的权限&#xff0c;权限不足。 当时…

实现B-树

一、概述 1.历史 B树&#xff08;B-Tree&#xff09;结构是一种高效存储和查询数据的方法&#xff0c;它的历史可以追溯到1970年代早期。B树的发明人Rudolf Bayer和Edward M. McCreight分别发表了一篇论文介绍了B树。这篇论文是1972年发表于《ACM Transactions on Database S…

解锁维特比算法:探寻复杂系统的最优解密码

引言 在复杂的技术世界中&#xff0c;维特比算法以其独特的魅力和广泛的应用&#xff0c;成为通信、自然语言处理、生物信息学等领域的关键技术。今天&#xff0c;让我们一同深入探索维特比算法的奥秘。 一、维特比算法的诞生背景 维特比算法由安德鲁・维特比在 1967 年提出…

CPU 100% 出现系统中断 怎么解决

CPU 100% 出现系统中断 怎么解决 电脑开机时会掉帧&#xff0c;切换到桌面时就会卡顿&#xff0c;然后打开任务管理器就会看到系统中断的cpu占用率达到100%&#xff0c;过一段时间再打开还是会有显示100%的占用率&#xff0c;这个问题怎么解决&#xff1f; 文章目录 CPU 100% …

Python 梯度下降法(五):Adam Optimize

文章目录 Python 梯度下降法&#xff08;五&#xff09;&#xff1a;Adam Optimize一、数学原理1.1 介绍1.2 符号说明1.3 实现流程 二、代码实现2.1 函数代码2.2 总代码2.3 遇到的问题2.4 算法优化 三、优缺点3.1 优点3.2 缺点 Python 梯度下降法&#xff08;五&#xff09;&am…

labelme_json_to_dataset ValueError: path is on mount ‘D:‘,start on C

这是你的labelme运行时label照片的盘和保存目的地址的盘不同都值得报错 labelme_json_to_dataset ValueError: path is on mount D:,start on C 只需要放一个盘但可以不放一个目录

中间件安全

一.中间件概述 1.中间件定义 介绍&#xff1a;中间件&#xff08;Middleware&#xff09;作为一种软件组件&#xff0c;在不同系统、应用程序或服务间扮演着数据与消息传递的关键角色。它常处于应用程序和操作系统之间&#xff0c;就像一座桥梁&#xff0c;负责不同应用程序间…

玩转大语言模型——配置图数据库Neo4j(含apoc插件)并导入GraphRAG生成的知识图谱

系列文章目录 玩转大语言模型——使用langchain和Ollama本地部署大语言模型 玩转大语言模型——ollama导入huggingface下载的模型 玩转大语言模型——langchain调用ollama视觉多模态语言模型 玩转大语言模型——使用GraphRAGOllama构建知识图谱 玩转大语言模型——完美解决Gra…

sizeof和strlen的对比与一些杂记

1.sizeof和strlen的对比 1.1sizeof &#xff08;1&#xff09;sizeof是一种操作符 &#xff08;2&#xff09;sizeof计算的是类型或变量所占空间的大小&#xff0c;单位是字节 注意事项&#xff1a; &#xff08;1&#xff09;sizeof 返回的值类型是 size_t&#xff0c;这是一…