寒假思维训练day19

 更新一道div3的F  和   做出来过的一道类似这个F的  icpc铜牌题, 美赛以后的第一篇。

 题目链接,有需自取:

div3 F链接:Problem - F - Codeforces

icpc Asia macau 铜牌题 Problem - K - Codeforces


摘要

Part1  div3 F 的题意、题解、代码(C++) 

Part2  2021 icpc macau 铜牌题 的题意、题解、代码(C++) 

Part3 回顾求倍增dp求Lca  和   kruskal  和   启发式合并优化的并查集


Part1 K. Link-Cut Tree: 

1、题意:

给定一个点数为n,边数为m的无向图,第i条边的长度是2^i,不包含自环和重边,图不一定连通,求出图中边权之和最小的简单环,简单环至少包含3个顶点。多组测试数据,n,m总和不大于1e6, 并且3 <= n <= 1e5, 1 <= m <= 1e5。如果图中不存在简单环就输出-1,否则输出按递增顺序排列的答案简单环边的索引。


2、题解:

我们知道边是2^i,由等比数列公式易得2^i = \sum_{j = 0}^{j = i - 1} 2^j + 1,我们欲想找到图中最小简单环不妨先对总体求一颗最小生成树,再遍历没使用过的边,找到第一条边所在的环就是题目中要求的最小环,我们记录这条边上的两点,因为边权是递增的并且每个都不同,我们反证一下,假设不是第一条边,我们设第一条边是2^j,第二条边必然满足2^j, j >= i + 1,显然它一定大于所有边累加之和,根据kruskal我们可以知道未选上的边的两点一定能通过比它边权更小的边合并到树中。

得证,显然如果没找到这样的边,原图就是一颗树,无解,反之,对于找到的边我们再加到生成树中,我们就得到了一颗基环树,再从记录好的边上的其中一点出发, 知道路径可以返回该点,记录边的编号,最后得到答案。


3、代码(C ++) 

#include <bits/stdc++.h>
#define int long long 
using namespace std;
const int N = 2e5; 
const int inf = 0x3f3f3f3f; 
int n, m; 
int h[N], ne[N << 1], e[N << 1], w[N << 1], idx; 
int p[N], cnt[N]; 
bool st[N]; 
int s, ed;  
int q[N], o;
bool flag;struct edge {int a, b, c; 
}eg[N << 1]; 
void add(int a, int b, int c) {e[idx] = b, ne[idx] = h[a], w[idx] = c, h[a] = idx ++; 
}
int find(int x) {if(x != p[x]) p[x] = find(p[x]); return p[x]; 
}void dfs(int u, int fa) {if(st[u]) {if(u == s) flag = 1; return; }st[u] = 1; for(int i = h[u]; ~i; i = ne[i]) {int j = e[i]; if(j == fa) continue; if(u == s && j == ed) continue; q[++ o] = w[i]; dfs(j, u); if(flag) return; -- o; }
}
void solve() {idx = 0; cin >> n >> m; for(int i = 0; i <= n; i ++ ) h[i] = -1, p[i] = i, cnt[i] = 1;  for(int i = 1; i <= m; i ++ ) {st[i] = 0;int u, v; cin >> u >> v;eg[i] = {u, v, i}; if(find(u) == find(v)) continue; if(cnt[find(u)] >= cnt[find(v)]) {cnt[find(u)] += cnt[find(v)]; p[find(v)] = find(u); }else {cnt[find(v)] += cnt[find(u)]; p[find(u)] = find(v); }add(u, v, i), add(v, u, i); st[i] = 1; }s = -1, ed = -1; for(int i = 1; i <= m; i ++ ) {if(st[i]) continue; int a = eg[i].a, b = eg[i].b, c = eg[i].c; add(a, b, c), add(b, a, c);  s = a, ed = b; break;    }if(s == -1) {cout << -1 << endl;return; }for(int i = 1; i <= n; i ++ ) st[i] = 0; o = 0; flag = 0; dfs(s, -1); sort(q + 1, q + 1 + o); for(int i = 1; i <= o; i ++ ) cout << q[i] << " \n"[i == o]; 
}
signed main() {ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); int ts; cin >> ts; while(ts -- ) solve(); return 0; 
}

Part2 F. Microcycle

1、题意:

给定一个点数为n,边数为m的无向图,没有重边和自环,图不一定连通,对于给定的图找到

一个最有简单环,使得环上最小边权小于等于图上其它简单环的环上最小边权,输出环上最小边权和换上点数,再按环的顺序输出点,一定有解。


2、题解:

我们有了上一题的基础,我们不妨对原图求一个最小生成树,这样我们得到了一个最小生成森林,我们遍历未被使用的边,此处一定是在一个连通块的点,我们不妨求一下这个环的最小边权,那怎么求呢,我们观察一下树上的两点V2和V7, 我们可以看到它们之间的最小值是从自己位置到最近公共祖先取min, 我们在维护Lca的同时维护一个最小值就可以O(logn)的求出任意两点间环的最小边权。



最后我们找到那条边,再通过Lca找点输出(具体见代码)。

3、代码(C ++)

#include <bits/stdc++.h>
#define int long long 
using namespace std; 
constexpr int N = 2e5 + 10, inf = 0x3f3f3f3f; 
int n, m;
int h[N], e[N << 1], ne[N << 1], w[N << 1], idx; 
int p[N], cnt[N]; 
int dep[N], fa[N][19], dis[N][19]; 
bool st[N]; 
struct edge {int a, b, c;bool operator< (const edge& W) const {return c < W.c;};
}eg[N << 1]; 
void add(int a, int b, int c) {e[idx] = b, ne[idx] = h[a], w[idx] = c, h[a] = idx ++; 
}
inline int find(int x) {if(x != p[x]) p[x] = find(p[x]); return p[x]; 
}
int q[N]; 
void bfs(int root) 
{int hh = 0, tt = -1;dep[root] = 1; fa[root][0] = 0;q[++ tt] = root; while(hh <= tt) {int t = q[hh ++]; for(int i = h[t]; ~i; i = ne[i]) {int j = e[i]; if(dep[j] > dep[t] + 1){dep[j] = dep[t] + 1; q[++ tt] = j; fa[j][0] = t; dis[j][0] = w[i]; for(int k = 1; k <= 18; k ++ ) fa[j][k] = fa[fa[j][k - 1]][k - 1],dis[j][k] = min(dis[j][k - 1],dis[fa[j][k - 1]][k - 1]); }}}
}
int Lca_Distance(int a, int b) {int ans = inf; if(dep[a] <= dep[b]) swap(a, b); for(int i = 18; i >= 0; i -- ) if(dep[fa[a][i]] >= dep[b]) {ans = min(ans, dis[a][i]); a = fa[a][i]; }if(a == b) return ans; for(int i = 18; i >= 0; i -- ) if(fa[a][i] != fa[b][i]) {ans = min(ans, dis[a][i]), ans = min(ans, dis[b][i]); a = fa[a][i], b = fa[b][i]; }  ans = min(ans, dis[b][0]), ans = min(ans, dis[a][0]); return ans; 
}
int Lca(int a, int b) {if(dep[a] <= dep[b]) swap(a, b); for(int i = 18; i >= 0; i -- ) if(dep[fa[a][i]] >= dep[b]) a = fa[a][i]; if(a == b) return a;  for(int i = 18; i >= 0; i -- ) if(fa[a][i] != fa[b][i]) a = fa[a][i], b = fa[b][i]; return fa[a][0]; 
}int q1[N], q2[N], c1, c2; 
void solve() {idx = 0; scanf("%lld%lld", &n, &m); for(int i = 0; i <= n; i ++ ) for(int j = 0; j <= 18; j ++ ) dis[i][j] = inf, fa[i][j] = 0; for(int i = 0; i <= n; i ++ ) h[i] = -1, cnt[i] = 1, p[i] = i, dep[i] = inf;dep[0] = 0; for(int i = 1; i <= m; i ++ ) {st[i] = 0; int a, b, c; scanf("%lld%lld%lld", &a,&b,&c);eg[i] = {a, b, c}; }sort(eg + 1, eg + 1 + m); for(int i = 1; i <= m; i ++ ) {int a = eg[i].a, b = eg[i].b, c = eg[i].c;if(find(a) == find(b)) continue;if(cnt[find(a)] >= cnt[find(b)]) {cnt[find(a)] += cnt[find(b)]; p[find(b)] = find(a); }else {cnt[find(b)] += cnt[find(a)]; p[find(a)] = find(b); }st[i] = 1; add(a, b, c), add(b, a, c); }for(int i = 1; i <= n; i ++ ) if(find(i) == i && cnt[i] >= 3) bfs(i); int s, ed, res = inf; for(int i = 1; i <= m; i ++ ) {if(st[i]) continue;int a = eg[i].a, b = eg[i].b, c = eg[i].c;int v = Lca_Distance(a, b); if(v < res) {res = v; s = a, ed = b; } }    int Lc = Lca(s, ed); c1 = 0, c2 = 0; while(s && dep[s] >= dep[Lc]) q1[++ c1] = s, s = fa[s][0]; while(ed && dep[ed] > dep[Lc]) q2[++ c2] = ed, ed = fa[ed][0];printf("%lld %lld\n", res, c1 + c2); for(int i = 1; i <= c1; i ++ ) printf("%lld ",q1[i]); for(int i = c2; i >= 1; i -- ) printf("%lld ", q2[i]); printf("\n"); 
}
signed main() {int ts; scanf("%lld",&ts); while(ts -- ) solve(); 
}

Part3  算法回顾:

1、倍增Lca模板

#include <iostream> 
#include <cstdio> 
#include <cstring>  
#include <algorithm> 
using namespace std; 
const int N = 4e4 + 10, M = N * 2, INF = 0x3f3f3f3f; 
int n, m, k;
int fa[N][16], dist[N];
int h[N], e[M], ne[M], idx; 
int root; 
int q[N]; 
void add(int a, int b) 
{e[idx] = b, ne[idx] = h[a], h[a] = idx ++; 
}
void bfs(int rot) 
{int hh = 0, tt = -1; memset(dist, 0x3f, sizeof dist); dist[0] = 0, dist[rot] = 1; fa[rot][0] = 0;q[++ tt] = rot; while(hh <= tt) {int t = q[hh ++]; for(int i = h[t]; ~i; i = ne[i]) {int j = e[i]; if(dist[j] > dist[t] + 1){dist[j] = dist[t] + 1; q[++ tt] = j; fa[j][0] = t; for(int k = 1; k <= 15; k ++ ) fa[j][k] = fa[fa[j][k - 1]][k - 1]; }}}
}
int lca(int a, int b) 
{if(dist[a] <= dist[b]) swap(a, b); for(int i = 15; i >= 0; i -- ) if(dist[fa[a][i]] >= dist[b]) a = fa[a][i]; if(a == b) return a; for(int i = 15; i >= 0; i -- ) if(fa[a][i] != fa[b][i]) a = fa[a][i], b = fa[b][i]; return fa[a][0]; 
}
int main() 
{memset(h, -1, sizeof h); cin >> n; for(int i = 1; i <= n; i ++ ) {int a, b; cin >> a >> b; if(b == -1) root = a; else add(a, b), add(b, a); }bfs(root); cin >> m; while(m --) {int x, y; cin >> x >> y; int Fa = lca(x, y); if(Fa == x) puts("1");else if(Fa == y) puts("2"); else puts("0"); }return 0; 
}


2、kruskal模板:

#include<iostream>
#include<algorithm> 
#include<cstring> 
using namespace std; 
const int N = 2e5 + 10, M = 1e5 + 10, INF = 0x3f3f3f3f;  
int n, m; 
int p[M]; 
struct edg
{int a, b, w;bool operator < (const edg &W) const {return w < W.w; }; 
}es[N];  
int find(int x) 
{if(p[x] != x) p[x] = find(p[x]); return p[x]; 
}
int kurstal() 
{sort(es, es + m); for(int i = 1; i <= n; i ++) p[i] = i; int res = 0, cnt = 0;  for(int i = 0; i < m; i ++) {int a = find(es[i].a), b = find(es[i].b), w = es[i].w; if(a != b) {p[a] = b; res += w; cnt ++; }}if(cnt < n - 1 ) return INF; return res; 
}
int main() 
{scanf("%d%d", &n, &m); for(int i = 0; i < m; i ++) {int x, y, z; scanf("%d%d%d", &x, &y, &z); es[i] = {x, y, z}; }int t = kurstal(); if(t == INF) puts("impossible"); else printf("%d\n", t);return 0; 
}

3、大块合并小块,启发式合并并查集

inline int find(int x) {if(x != p[x]) p[x] = find(p[x]); return p[x]; 
}if(find(a) == find(b)) continue;
if(cnt[find(a)] >= cnt[find(b)]) {cnt[find(a)] += cnt[find(b)]; p[find(b)] = find(a); 
}
else {cnt[find(b)] += cnt[find(a)]; p[find(a)] = find(b); 
}




 


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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SolidWorks学习笔记——草图绘制的基本命令

目录 一、进入草图绘制 二、直线命令与删除命令 三、圆弧命令与矩形命令 四、槽口命令以及多边形命令 五、椭圆以及倒角命令 六、草图绘制中的剪裁命令 七、草图中的几何关系 八、草图绘制中的智能尺寸 九、从外部粘贴草图&#xff08;CAD&#xff09; 一、进入草图绘…

Node.js之npm单独与批量升级依赖包的方式

Node.js之npm单独与批量升级依赖包的方式 文章目录 Node.js之npm单独与批量升级依赖包的方式npm查看与升级依赖包1. 单独安装或升级最新版本2. 查看依赖但不升级1. npm outdated2. npm update 3. 批量升级新版本4. npm-check-updates1. 全局安装2. ncu查看可升级的版本3. 升级依…

MATLAB实现LSTM时间序列预测

LSTM模型可以在一定程度上学习和预测非平稳的时间序列,其具有强大的记忆和非线性建模能力,可以捕捉到时间序列中的复杂模式和趋势[4]。在这种情况下,LSTM模型可能会自动学习到时间序列的非平稳性,并在预测中进行适当的调整。其作为循环神经网络(RNN)的特殊形式,继承了循…

项目02《游戏-09-开发》Unity3D

基于 项目02《游戏-08-开发》Unity3D &#xff0c; 本次任务是做抽卡界面&#xff0c;获取的卡片增添在背包中&#xff0c;并在背包中可以删除卡片&#xff0c; 首先在Canvas下创建一个空物体&#xff0c;命名为LotteryPanel&#xff0c;作为抽卡界面&#xff0c; …

MyBatis之动态代理实现增删改查以及MyBatis-config.xml中读取DB信息文件和SQL中JavaBean别名配置

MyBatis之环境搭建以及实现增删改查 前言实现步骤1. 编写MyBatis-config.xml配置文件2. 编写Mapper.xml文件&#xff08;增删改查SQL文&#xff09;3. 定义PeronMapper接口4. 编写测试类1. 执行步骤2. 代码实例3. 运行log 开发环境构造图总结 前言 上一篇文章&#xff0c;我们…

PySpark(三)RDD持久化、共享变量、Spark内核制度,Spark Shuffle、Spark执行流程

目录 RDD持久化 RDD 的数据是过程数据 RDD 缓存 RDD CheckPoint 共享变量 广播变量 累加器 Spark 内核调度 DAG DAG 的宽窄依赖和阶段划分 内存迭代计算 Spark是怎么做内存计算的? DAG的作用?Stage阶段划分的作用? Spark为什么比MapReduce快&#xff1f; Spa…

Could not connect to Redis at 127.0.0.1:6379:由于目标计算机积极拒绝,无法连接...问题解决方法之一

一、问题描述 将Redis压缩包解压后&#xff0c;安装Redis过程中出现问题Could not connect to Redis at 127.0.0.1:6379:由于目标计算机积极拒绝&#xff0c;无法连接... 官网windows下redis开机自启动的指令如下&#xff1a; 1、在redis目录下执行 redis-server --service-in…

GEE Colab——如何利用Matplotlib在colab中进行图形制作

在colab中绘制图表 笔记本的一个常见用途是使用图表进行数据可视化。Colaboratory 提供多种图表工具作为 Python 导入,让这一工作变得简单。 Matplotlib Matplotlib 是最常用的图表工具包,详情请查看其文档,并通过示例获得灵感。 线性图 线性图是一种常见的图表类型,用…

按键扫描16Hz-单片机通用模板

按键扫描16Hz-单片机通用模板 一、按键扫描的原理1、直接检测高低电平类型2、矩阵扫描类型3、ADC检测类型二、key.c的实现1、void keyScan(void) 按键扫描函数①void FHiKey(void) 按键按下功能②void FSameKey(void) 按键长按功能③void FLowKey(void) 按键释放功能三、key.h的…

JavaScript综合练习2

JavaScript 综合练习 2 1. 案例演示 2. 代码实现 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta name"viewport" content"widthdevice-width, initial-scale1.0" /><title&…

Springboot根据环境读取application配置文件

目录 1. 首先创建两个不同配置文件 2. pom.xml 配置文件 3. 指定环境 4. 最后启动测试 1. 首先创建两个不同配置文件 分别为开发环境和生产环境 application-dev.properties 和 application-prod.properties application-dev.properties 配置为 1931 端口 application-pro…

放假--寒假自学版 day1(补2.5)

fread 函数&#xff1a; 今日练习 C语言面试题5道~ 1. static 有什么用途&#xff1f;&#xff08;请至少说明两种&#xff09; 1) 限制变量的作用域 2) 设置变量的存储域 2. 引用与指针有什么区别&#xff1f; 1) 引用必须被初始化&#xff0c;指针不必。 2) 引用初始…

【大数据】Flink 中的 Slot、Task、Subtask、并行度

Flink 中的 Slot、Task、Subtask、并行度 1.并行度2.Task 与线程3.算子链与 slot 共享资源组4.Task slots 与系统资源5.总结 我们在使用 Flink 时&#xff0c;经常会听到 task&#xff0c;slot&#xff0c;线程 以及 并行度 这几个概念&#xff0c;对于初学者来说&#xff0c;这…

【网工】华为设备命令学习(服务器发布)

本次实验主要是内网静态nat配置没&#xff0c;对外地址可以理解为一台内网的服务器&#xff0c;外网设备可以ping通内网的服务器设备&#xff0c;但是ping不通内网的IP。 除了AR1设备配置有区别&#xff0c;其他设备都是基础IP的配置。 [Huawei]int g0/0/0 [Huawei-GigabitEt…

双指针和单调栈

双指针 用于解决一类基于子段的统计问题 子段就是&#xff1a;数组中连续的一段 可以用一个闭区间来表示数组中的连续一段 这个方法核心就是优化&#xff1a;两种循环的枚举 也就是枚举左端点l和右端点r的所有可能优化关键就是&#xff1a;去除枚举中的冗余部分 具体优化策略…

设计模式-行为型模式(下)

1.访问者模式 访问者模式在实际开发中使用的非常少,因为它比较难以实现并且应用该模式肯能会导致代码的可读性变差,可维护性变差,在没有特别必要的情况下,不建议使用访问者模式. 访问者模式(Visitor Pattern) 的原始定义是&#xff1a; 允许在运行时将一个或多个操作应用于一…

【linux开发工具】vim详解

&#x1f4d9; 作者简介 &#xff1a;RO-BERRY &#x1f4d7; 学习方向&#xff1a;致力于C、C、数据结构、TCP/IP、数据库等等一系列知识 &#x1f4d2; 日后方向 : 偏向于CPP开发以及大数据方向&#xff0c;欢迎各位关注&#xff0c;谢谢各位的支持 “学如逆水行舟&#xff0…

自适应二次元404页面源码

自适应二次元404页面源码&#xff0c;HTMLCSSJS,喜欢二次元的朋友可以下载使用 蓝奏云&#xff1a;https://wfr.lanzout.com/iuPNQ1ns7dxg

多模态对比语言图像预训练CLIP:打破语言与视觉的界限,具备零样本能力

多模态对比语言图像预训练CLIP:打破语言与视觉的界限,具备零样本能力。 一种基于多模态(图像、文本)对比训练的神经网络。它可以在给定图像的情况下,使用自然语言来预测最相关的文本片段,而无需为特定任务进行优化。CLIP的设计类似于GPT-2和GPT-3,具备出色的零射击能力…

API接口访问鉴权设计和实现的经验总结

API接口访问鉴权是保护API资源安全的重要措施。本文总结了一些常见的API接口访问鉴权设计和实现方法&#xff0c;以帮助开发人员更好地理解和应用这些技术。 1. 什么是API接口访问鉴权&#xff1f; - 解释了API接口访问鉴权的基本概念和作用&#xff0c;以及为什么需要对A…