Codeforces 757F. Team Rocket Rises Again 最短路 + 支配树

题意:

给你 n 个点, m 条双向边,求爆了某个点后,从s出发的最短路距离,会改变最多的数量。

分析:

建出最短路树(DAG)之后,在最短路树上跑一下支配树,找出支配的点。答案就是爆支配点的收益,即为该点支配的 size。上支配树模板即可。支配树教程:oi-wiki 板子
支配树算法用的是 Lengauer-Tarjan,简单讲一下,首先是支配树里面的定义:
u的半支配点 指的是dfn最小的v(v<u) 满足v到u存在一条路径 路径中所有点dfn 都 > u

两条定理,对应的是函数 LengauerTarjan 里的写法:

  1. u的半支配点是 大于u的所有祖先的半支配点中最小的节点,
  2. sdom(u) 到 u 路径中所有节点 v 都满足 sdom(v) >= sdom(u),则 idom(u) = sdom(u)

代码:

#include <bits/stdc++.h>
#define N 200005using namespace std;struct MAP {struct Edge {int x, y, nex;long long d;} edge[N * 5];int len, fir[N];void init(){len = 0;memset(fir, -1, sizeof fir);}void addEdge(int x,int y){len++; edge[len].x=x; edge[len].y=y; edge[len].nex = fir[x]; fir[x] = len;    }void addEdge(int x, int y, long long d){len++; edge[len].x=x; edge[len].y=y; edge[len].d=d; edge[len].nex=fir[x]; fir[x]=len;}
};
MAP input;
MAP G, GF;
MAP dfsTree, dfsTreeF;
MAP dominate;queue<int> q;
bool vis[N];
long long dis[N];
int n, m, s;void SPFA()
{memset(vis, 0, sizeof vis);memset(dis, 126, sizeof dis);q.push(s);dis[s] = 0;vis[s] = 1;while (!q.empty()) {int x = q.front();q.pop();vis[x] = 0;for (int k = G.fir[x]; k != -1; k = G.edge[k].nex) {int y = G.edge[k].y;if (dis[y] > dis[x] + G.edge[k].d) {dis[y] = dis[x] + G.edge[k].d;if (!vis[y]) {vis[y] = 1;q.push(y);}}}}
}struct DominatorTree {DominatorTree(){tot = 0;}int id[N], dfn[N], fa[N], tot;int anc[N], sdom[N], mn[N];int in[N];int dp[N][21], dep[N];int idom[N];int dominateSize[N];int Find(int x) {if(x != anc[x]) {int t = anc[x];anc[x] = Find(anc[x]);if(dfn[sdom[mn[x]]] > dfn[sdom[mn[t]]]) {mn[x] = mn[t];}}return anc[x];}void Dfs(int x) {dfn[x] = ++tot;id[tot] = x;for (int k = G.fir[x]; k != -1; k = G.edge[k].nex) {int y = G.edge[k].y;if (!dfn[y]) {Dfs(y);fa[y] = x;dfsTree.addEdge(x, y);}}}void LengauerTarjan() {for(int i = 1; i <= n; i++) {anc[i] = i;sdom[i] = i;mn[i] = i;}for(int i = n; i >= 2; i--) {int x = id[i];if(!x) continue;int pos = i;for(int k = GF.fir[x]; k != -1; k = GF.edge[k].nex) {int y = GF.edge[k].y; // pre// if(!dfn[y]) continue;if(dfn[y] < dfn[x]) {pos = min(pos, dfn[y]);} else {Find(y); // find pos = min(pos, dfn[sdom[mn[y]]]);}}sdom[x] = id[pos];anc[x] = fa[x];dfsTree.addEdge(sdom[x], x);}}int LCA(int x, int y) {if (dep[x] < dep[y]) {swap(x, y);}int deep = dep[x] - dep[y];for (int i = 20; i >= 0; i--) {if (deep >= (1 << i)) {deep -= (1 << i);x = dp[x][i];}}if (x == y) {return x;}for (int i = 20; i >= 0; i--) {if (dp[x][i] != dp[y][i]) {x = dp[x][i];y = dp[y][i];}}return dp[x][0];}void BuildDominate(int x) {int to = dfsTreeF.edge[dfsTreeF.fir[x]].y;for(int k = dfsTreeF.fir[x]; k != -1; k = dfsTreeF.edge[k].nex) {int y = dfsTreeF.edge[k].y;to = LCA(to, y);}idom[x] = to;dep[x] = dep[to] + 1;dp[x][0] = to;dominate.addEdge(to, x);for(int i = 1; i <= 20; i++) dp[x][i] = dp[dp[x][i-1]][i-1];}void TopSort() {for (int x = 1; x <= n; x++) {for(int k = dfsTree.fir[x]; k != -1; k = dfsTree.edge[k].nex) {int y = dfsTree.edge[k].y;in[y] ++;dfsTreeF.addEdge(y, x);}}for(int x = 1; x <= n; x++) {if(!in[x]) {in[x] ++;dfsTree.addEdge(0, x);dfsTreeF.addEdge(x, 0);}}queue<int> q;q.push(0);while(!q.empty()) {int x = q.front();q.pop();for(int k = dfsTree.fir[x]; k != -1; k = dfsTree.edge[k].nex) {int y = dfsTree.edge[k].y;in[y] --;if(in[y] == 0) {q.push(y);BuildDominate(y);}}}}void DfsDominate(int x) {dominateSize[x] = 1;for(int k = dominate.fir[x]; k != -1; k = dominate.edge[k].nex) {int y = dominate.edge[k].y;DfsDominate(y);dominateSize[x] += dominateSize[y];}}void Run(int s) {dfsTree.init();dfsTreeF.init();dominate.init();Dfs(s);LengauerTarjan();TopSort();DfsDominate(s);}} dominatorTree;int main() {cin.tie(0);ios::sync_with_stdio(false);cin >> n >> m >> s;G.init();for (int i = 1; i <= m; i++) {cin >> input.edge[i].x >> input.edge[i].y >> input.edge[i].d;G.addEdge(input.edge[i].x, input.edge[i].y, input.edge[i].d);G.addEdge(input.edge[i].y, input.edge[i].x, input.edge[i].d);}SPFA();G.init();GF.init();for (int i = 1; i <= m; i++) {if (dis[input.edge[i].y] == dis[input.edge[i].x] + input.edge[i].d) {G.addEdge(input.edge[i].x, input.edge[i].y);GF.addEdge(input.edge[i].y, input.edge[i].x); } else if (dis[input.edge[i].x] == dis[input.edge[i].y] + input.edge[i].d) {G.addEdge(input.edge[i].y, input.edge[i].x);GF.addEdge(input.edge[i].x, input.edge[i].y);}}dominatorTree.Run(s);int res = 0;for(int i = 1; i <= n; i++) {if(i == s) continue;res = max(res, dominatorTree.dominateSize[i]);}cout << res << endl;return 0;
}

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

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

相关文章

链表OJ详解

&#x1f495;人生不满百&#xff0c;常怀千岁忧&#x1f495; 作者&#xff1a;Mylvzi 文章主要内容&#xff1a;链表oj详解 题目一&#xff1a;移除元素 题目要求&#xff1a; 画图分析&#xff1a; 代码实现&#xff1a; struct ListNode* removeElements(struct List…

flutter项目 环境搭建

开发flutter项目 搭建工具环境 flutter项目本身 所需开发工具环境 flutter 谷歌公司开发 系统支持库 镜像库 搭建流程&#xff1a; flutter 官网&#xff1a; https://flutter.dev/community/china //步骤1 .bash_profile touch .bash_profile pwd /Users/haijunyan open ~ e…

商品首页(sass+git本地初始化)

目录 安装sass/sass-loader 首页(vue-setup) 使用git本地提交 同步远程git库 安装sass/sass-loader #安装sass npm i sass -D#安装sass-loader npm i sass-loader10.1.1 -D 首页(vue-setup) <template><view class"u-wrap"><!-- 轮播图 --><…

C++lambda表达式

先来说背景&#xff1a;当我们需要对一些的元素进行排序的时候&#xff0c;可以使用std::sort来进行排序&#xff0c;而当需要对一些自定义类型的元素来排序的时候&#xff0c;要去写一个类&#xff0c;或者说是需要写一个仿函数&#xff0c;而如果功能要求上需要根据不同的比较…

基于chatgpt动手实现一个ai_translator

动手实现一个ai翻译 前言 最近在极客时间学习《AI 大模型应用开发实战营》&#xff0c;自己一边跟着学一边开发了一个进阶版本的 OpenAI-Translator&#xff0c;在这里简单记录下开发过程和心得体会&#xff0c;供有兴趣的同学参考&#xff1b; ai翻译程序 版本迭代 在学习…

VLC播放主要流程

前言 VLC 播放流程大概是先加载解封装器,然后通过es_out控制所有的stream。然后会加载decoder。最终通过resource文件的方法交给输出 模块。下面简要介绍。 正文 播放器主要分为三层。主要通过两个接口实现了功能隔离。分别是es_out.c和decoder.c的实现了&#xff1a; //控…

算法练习-搜索 相关

文章目录 迷宫问题 迷宫问题 定义一个二维数组 m行 * n列 &#xff0c;如 4 5 数组下所示&#xff1a; int arr[5][5] { 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, }; 它表示一个迷宫&#xff0c;1表示墙壁&#xff0c;0表示可以走的路&#xff0c;只…

Synchronized八锁

/** * Description: 8 锁 * 1 标准访问&#xff0c;先打印短信还是邮件 ------sendSMS ------sendEmail 2 停 4 秒在短信方法内&#xff0c;先打印短信还是邮件 ------sendSMS ------sendEmail 3 新增普通的 hello 方法&#xff0c;是先打短信还是 hello ------getHello ------…

Idea中使用statement接口对象,显示mysql版本号,所有库和表名

使用statement 接口对象&#xff0c;进行以下操作&#xff1a; 显示数据库版本号显示所有库显示所有库中的table表 显示数据库版本号&#xff1a; public class StatementDemo {Testvoid showall(){try{Statement st conn.createStatement();ResultSet rs st.executeQuery(…

pytest fixture 常用参数

fixture 常用的参数 参数一&#xff1a;autouse&#xff0c;作用&#xff1a;自动运行&#xff0c;无需调用 举例一&#xff1a;我们在类中定义一个function 范围的fixture; 设置它自动执行autouseTrue&#xff0c;那么我们看下它执行结果 输出&#xff1a; 说明&#xff1a;…

Leetcode-每日一题【剑指 Offer 12. 矩阵中的路径】

题目 单词必须按照字母顺序&#xff0c;通过相邻的单元格内的字母构成&#xff0c;其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。 例如&#xff0c;在下面的 34 的矩阵中包含单词 "ABCCED"&#xff08;单词中的字母…

CUDA执行模型

一、CUDA执行模型概述 二、线程束执行 1. 线程束与线程块 线程束是SM中基本的执行单元。 当一个线程块的网格被启动后&#xff0c;网格中的线程块分布在SM中。 一旦线程块被调度到一个SM中&#xff0c;线程块中的线程会被进一步划分成线程束。 一个线程束由32个连续的线程…

【Express.js】数据库初始化

数据库初始化 在软件开发阶段和测试阶段&#xff0c;为了方便调试&#xff0c;我们通常会进行一系列的数据库初始化操作&#xff0c;比如重置数据表&#xff0c;插入记录等等&#xff0c;或者在部署阶段进行数据初始化的操作 根据前面章节介绍过的 knex.js 和 sequelize.js&…

基于自适应曲线阈值和非局部稀疏正则化的压缩感知图像复原研究【自适应曲线阈值去除加性稳态白/有色高斯噪声】(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

什么是媒体代发布?媒体代发布注意事项

传媒如春雨&#xff0c;润物细无声&#xff0c;大家好&#xff0c;我是51媒体网胡老师。 媒体代发布是指将新闻稿或其他宣传内容委托给专业的媒体代理机构或公司进行发布和推广的活动。这些机构通常拥有丰富的媒体资源、人脉和经验&#xff0c;能够更好地将信息传递给目标受众…

C语言 指针与内存之间的关系

一、内存与字节 一个内存单元一个字节一个地址 整型 int 类型中int类型的字节数是4 且一个字节表示八个bite位 一个二进制数位有着32个bite 所以又可以表示为&#xff1a;一个字节 8个比特位 32位数的二进制数位的八分之一 例如&#xff1a; int a 10&#xff1b; 该表达式…

项目实战 — 消息队列(9){编写demo程序}

消息队列服务器核心功能就是&#xff0c;提供了虚拟主机&#xff0c;交换机&#xff0c; 队列&#xff0c;消息等概念的管理&#xff0c;实现三种典型的消息转发方式&#xff0c;可以实现跨主机/服务器之间的生产者消费模型。 这里&#xff0c;就编写一个demo&#xff0c;实现…

【实战讲解】数据血缘落地实施

‍在复杂的社会分工协作体系中&#xff0c;我们需要明确个人定位&#xff0c;才能更好的发挥价值&#xff0c;数据也是一样&#xff0c;于是&#xff0c;数据血缘应运而生。 今天这篇文章会全方位的讲解数据血缘&#xff0c;并且给出具体的落地实施方案。 一、数据血缘是什么…

JAVA多线程和并发基础面试问答(翻译)

JAVA多线程和并发基础面试问答(翻译) java多线程面试问题 1. 进程和线程之间有什么不同&#xff1f; 一个进程是一个独立(self contained)的运行环境&#xff0c;它可以被看作一个程序或者一个应用。而线程是在进程中执行的一个任务。Java运行环境是一个包含了不同的类和程序…

苏州OV泛域名RSA加密算法https

RSA加密算法是一种非对称加密算法&#xff0c;它被广泛应用于信息安全领域。与对称加密算法不同&#xff0c;RSA加密算法使用了两个密钥&#xff0c;一个公钥和一个私钥。公钥可以公开&#xff0c;任何人都可以使用它加密信息&#xff0c;但只有私钥的持有者才能解密信息。RSA加…