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.pswp.cn/news/35402.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/35402.shtml
英文地址,請注明出處:http://en.pswp.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加…