【一百零三】【算法分析與設計】并查集,并查集的實現,P3367 【模板】并查集

并查集的實現

描述

給定一個沒有重復值的整形數組arr,初始時認為arr中每一個數各自都是一個單獨的集合。請設計一種叫UnionFind的結構,并提供以下兩個操作。

boolean isSameSet(int a, int b): 查詢a和b這兩個數是否屬于一個集合

void union(int a, int b): 把a所在的集合與b所在的集合合并在一起,原本兩個集合各自的元素以后都算作同一個集合

[要求]

如果調用isSameSet和union的總次數逼近或超過O(N),請做到單次調用isSameSet或union方法的平均時間復雜度為O(1)

輸入描述:

第一行兩個整數N, M。分別表示數組大小、操作次數 接下來M行,每行有一個整數opt 若opt = 1,后面有兩個數x, y,表示查詢(x, y)這兩個數是否屬于同一個集合 若opt = 2,后面有兩個數x, y,表示把x, y所在的集合合并在一起

輸出描述:

對于每個opt = 1的操作,若為真則輸出"Yes",否則輸出"No"

示例1

輸入:

4 5
1 1 2
2 2 3
2 1 3
1 1 1
1 2 3

復制

輸出:

No
Yes
Yes

復制

說明:

每次2操作后的集合為 ({1}, {2}, {3}, {4}) ({1}, {2, 3}, {4}) ({1, 2, 3}, {4})

備注:

1 ? N , M ? 1 0 6 1 ? N , M ? 1 0 6 1 \leqslant N, M \leqslant 10^6\\1?N,M?10^6 1?N,M?1061?N,M?106

保證 1 ? x , y ? N 1 \leqslant x, y \leqslant N 1?x,y?N
保證 1 ? x , y ? N 1?x,y?N 1?x,y?N

在這里插入圖片描述
在這里插入圖片描述

一般寫法

#include<bits/stdc++.h>
using namespace std;#define int long long
#define endl '\n'
#define FAST() ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)#define p pair<int,int> 
#define ff first
#define ss second #define ltu(i,a,b) for(int i=a;i<=b;i++)
#define utl(i,a,b) for(int i=a;i>=b;i--)int n,m; // 定義兩個整型變量n和m,表示數組大小和操作次數
struct node{int op,x,y; // 定義一個結構體node,包含三個整型變量op, x, y
};
vector<node> readd; // 定義一個存儲node結構體的向量readdvector<int>father; // 定義一個整型向量father,用來存儲每個節點的父節點
vector<int>stackk; // 定義一個整型向量stackk,用來存儲路徑上的節點// findd函數用于查找節點i的根節點
int findd(int i){while(!(father[i]==i)){ // 如果節點i不是自己的父節點i=father[i]; // 將i更新為它的父節點stackk.push_back(i); // 將節點i壓入stackk}while(!stackk.empty()){ // 當stackk不為空時father[stackk.back()]=i; // 將stackk中的每個節點的父節點更新為istackk.pop_back(); // 彈出stackk的最后一個元素}return i; // 返回根節點
}// isSameSet函數用于判斷兩個節點x和y是否屬于同一個集合
bool isSameSet(int x,int y){return findd(x)==findd(y); // 比較x和y的根節點是否相同
}// unionn函數用于將兩個節點x和y所在的集合合并
void unionn(int x,int y){father[findd(x)]=findd(y); // 將x的根節點的父節點設為y的根節點
}// solve函數用于處理所有的操作
void solve(){father.assign(n+5,0); // 初始化father向量,大小為n+5stackk.clear(); // 清空stackkltu(i,0,n+5-1){ // 遍歷每個節點father[i]=i; // 初始化每個節點的父節點為自己}for(auto&xx:readd){ // 遍歷所有的操作if(xx.op==1){ // 如果操作類型為1,表示查詢操作if(isSameSet(xx.x,xx.y)){ // 判斷x和y是否屬于同一個集合cout<<"Yes"<<endl; // 是同一個集合則輸出Yes}else{cout<<"No"<<endl; // 否則輸出No}}else{ // 如果操作類型為2,表示合并操作unionn(xx.x,xx.y); // 合并x和y所在的集合}}
}// main函數是程序的入口
signed main(){FAST(); // 加速輸入輸出cin>>n>>m; // 輸入n和mreadd.clear(); // 清空readd向量ltu(i,1,m){ // 遍歷m次node temp; // 定義一個臨時node變量cin>>temp.op>>temp.x>>temp.y; // 輸入操作類型和對應的x, yreadd.push_back(temp); // 將temp壓入readd向量}solve(); // 調用solve函數處理操作
}

進階寫法

在這里插入圖片描述

#include<bits/stdc++.h> // 引入所有標準庫頭文件
using namespace std;#define int long long // 使用長整型定義int,方便處理大數
#define endl '\n' // 定義換行符
#define FAST() ios::sync_with_stdio(0),cin.tie(0),cout.tie(0) // 加速輸入輸出#define p pair<int,int> // 定義一個整型對的類型別名
#define ff first // 定義first的別名
#define ss second // 定義second的別名#define ltu(i,a,b) for(int i=a;i<=b;i++) // 定義從a到b的循環
#define utl(i,a,b) for(int i=a;i>=b;i--) // 定義從a到b的逆向循環int n,m; // 定義兩個長整型變量n和m,表示元素個數和操作次數
struct node{int op,x,y; // 定義一個結構體node,包含三個長整型變量op, x, y
};
vector<node> readd; // 定義一個存儲node結構體的向量readd
vector<int> father; // 定義一個長整型向量father,用來存儲每個節點的父節點// findd函數用于查找節點i的根節點
int findd(int i){if(father[i]!=i) father[i]=findd(father[i]); // 如果節點i不是自己的父節點,遞歸查找父節點并路徑壓縮return father[i]; // 返回根節點
}// solve函數用于處理所有的操作
void solve(){father.assign(n+5,0); // 初始化father向量,大小為n+5ltu(i,0,n+5-1){ // 遍歷每個節點father[i]=i; // 初始化每個節點的父節點為自己}for(auto& xx : readd){ // 遍歷所有的操作if(xx.op == 1){ // 如果操作類型為1,表示查詢操作if(findd(xx.x) == findd(xx.y)){ // 判斷x和y的根節點是否相同cout << "Yes" << endl; // 是同一個集合則輸出Yes} else {cout << "No" << endl; // 否則輸出No}} else { // 如果操作類型為2,表示合并操作father[findd(xx.x)] = findd(xx.y); // 將x的根節點的父節點設為y的根節點}}
}// main函數是程序的入口
signed main(){FAST(); // 加速輸入輸出cin >> n >> m; // 輸入n和mreadd.clear(); // 清空readd向量ltu(i,1,m){ // 遍歷m次node temp; // 定義一個臨時node變量cin >> temp.op >> temp.x >> temp.y; // 輸入操作類型和對應的x, yreadd.push_back(temp); // 將temp壓入readd向量}solve(); // 調用solve函數處理操作
}

P3367 【模板】并查集

【模板】并查集

題目描述

如題,現在有一個并查集,你需要完成合并和查詢操作。

輸入格式

第一行包含兩個整數 N , M N,M N,M ,表示共有 N N N 個元i素和 M M M 個操作。

接下來 M M M 行,每行包含三個整數 Z _ i , X _ i , Y _ i Z\_i,X\_i,Y\_i Z_i,X_i,Y_i

Z _ i = 1 Z\_i=1 Z_i=1 時,將 X _ i X\_i X_i Y _ i Y\_i Y_i 所在的集合合并。

Z _ i = 2 Z\_i=2 Z_i=2 時,輸出 X _ i X\_i X_i Y _ i Y\_i Y_i 是否在同一集合內,是的輸出 Y ;否則輸出 N

輸出格式

對于每一個 Z _ i = 2 Z\_i=2 Z_i=2 的操作,都有一行輸出,每行包含一個大寫字母,為 Y 或者 N

樣例 #1

樣例輸入 #1

4 7
2 1 2
1 1 2
2 1 2
1 3 4
2 1 4
1 2 3
2 1 4

樣例輸出 #1

N
Y
N
Y

提示

對于 30 % 30\% 30% 的數據, N ≤ 10 , M ≤ 20 N \le 10,M \le 20 N10M20

對于 70 % 70\% 70% 的數據, N ≤ 100 , M ≤ 1 0 3 N \le 100,M \le 10^3 N100M103

對于 100 % 100\% 100% 的數據, 1 ≤ N ≤ 1 0 4 1\le N \le 10^4 1N104 1 ≤ M ≤ 2 × 1 0 5 1\le M \le 2\times 10^5 1M2×105 1 ≤ X _ i , Y _ i ≤ N 1 \le X\_i, Y\_i \le N 1X_i,Y_iN Z _ i ∈ { 1 , 2 } Z\_i \in \{ 1, 2 \} Z_i{1,2}

一般寫法

#include<bits/stdc++.h>
using namespace std;#define int long long // 使用長整型定義int,方便處理大數
#define endl '\n' // 定義換行符
#define FAST() ios::sync_with_stdio(0),cin.tie(0),cout.tie(0) // 加速輸入輸出#define p pair<int,int>
#define ff first
#define ss second 
#define ltu(i,a,b) for(int i=a;i<=b;i++) // 定義從a到b的循環
#define utl(i,a,b) for(int i=a;i>=b;i--) // 定義從a到b的逆向循環int n, m; // 定義兩個長整型變量n和m,表示元素個數和操作次數
struct node {int op, x, y; // 定義一個結構體node,包含三個長整型變量op, x, y
};
vector<node> readd; // 定義一個存儲node結構體的向量readdvector<int> father; // 定義一個長整型向量father,用來存儲每個節點的父節點
vector<int> st; // 定義一個長整型向量st,用來存儲路徑上的節點// findd函數用于查找節點i的根節點
int findd(int i) {while (!(father[i] == i)) { // 如果節點i不是自己的父節點i = father[i]; // 將i更新為它的父節點st.push_back(i); // 將節點i壓入st}while (!st.empty()) { // 當st不為空時father[st.back()] = i; // 將st中的每個節點的父節點更新為ist.pop_back(); // 彈出st的最后一個元素}return i; // 返回根節點
}// isSameSet函數用于判斷兩個節點x和y是否屬于同一個集合
bool isSameSet(int x, int y) {return findd(x) == findd(y); // 比較x和y的根節點是否相同
}// unionn函數用于將兩個節點x和y所在的集合合并
void unionn(int x, int y) {father[findd(x)] = findd(y); // 將x的根節點的父節點設為y的根節點
}// solve函數用于處理所有的操作
void solve() {father.assign(n + 5, 0); // 初始化father向量,大小為n+5ltu(i, 0, n + 5 - 1) { // 遍歷每個節點father[i] = i; // 初始化每個節點的父節點為自己}st.clear(); // 清空stfor (auto& xx : readd) { // 遍歷所有的操作int op = xx.op, x = xx.x, y = xx.y; // 獲取操作類型和對應的x, yif (op == 1) { // 如果操作類型為1,表示合并操作unionn(x, y); // 合并x和y所在的集合} else { // 如果操作類型為2,表示查詢操作if (isSameSet(x, y)) cout << "Y" << endl; // 是同一個集合則輸出Yelse cout << "N" << endl; // 否則輸出N}}
}// main函數是程序的入口
signed main() {FAST(); // 加速輸入輸出cin >> n >> m; // 輸入n和mreadd.clear(); // 清空readd向量ltu(i, 1, m) { // 遍歷m次node temp; // 定義一個臨時node變量cin >> temp.op >> temp.x >> temp.y; // 輸入操作類型和對應的x, yreadd.push_back(temp); // 將temp壓入readd向量}solve(); // 調用solve函數處理操作
}

進階寫法

#include<bits/stdc++.h> // 引入所有標準庫頭文件
using namespace std;#define int long long // 使用長整型定義int,方便處理大數
#define endl '\n' // 定義換行符
#define FAST() ios::sync_with_stdio(0) // 加速輸入輸出#define p pair<int,int> // 定義一個整型對的類型別名
#define ff first // 定義first的別名
#define ss second // 定義second的別名#define ltu(i,a,b) for(int i=a;i<=b;i++) // 定義從a到b的循環
#define utl(i,a,b) for(int i=a;i>=b;i--) // 定義從a到b的逆向循環int n, m; // 定義兩個長整型變量n和m,表示元素個數和操作次數
struct node {int op, x, y; // 定義一個結構體node,包含三個長整型變量op, x, y
};
vector<node> readd; // 定義一個存儲node結構體的向量readd
vector<int> father; // 定義一個長整型向量father,用來存儲每個節點的父節點// findd函數用于查找節點i的根節點
int findd(int i) {if (father[i] != i) father[i] = findd(father[i]); // 如果節點i不是自己的父節點,遞歸查找父節點并路徑壓縮return father[i]; // 返回根節點
}// solve函數用于處理所有的操作
void solve() {father.assign(n + 5, 0); // 初始化father向量,大小為n+5ltu(i, 0, n + 5 - 1) father[i] = i; // 初始化每個節點的父節點為自己for (auto& xx : readd) { // 遍歷所有的操作if (xx.op == 1) { // 如果操作類型為1,表示合并操作father[findd(xx.x)] = findd(xx.y); // 將x的根節點的父節點設為y的根節點} else { // 如果操作類型為2,表示查詢操作if (findd(xx.x) == findd(xx.y)) cout << "Y" << endl; // 是同一個集合則輸出Yelse cout << "N" << endl; // 否則輸出N}}
}// main函數是程序的入口
signed main() {FAST(); // 加速輸入輸出cin >> n >> m; // 輸入n和mltu(i, 1, m) { // 遍歷m次node temp; // 定義一個臨時node變量cin >> temp.op >> temp.x >> temp.y; // 輸入操作類型和對應的x, yreadd.push_back(temp); // 將temp壓入readd向量}solve(); // 調用solve函數處理操作
}

結尾

最后,感謝您閱讀我的文章,希望這些內容能夠對您有所啟發和幫助。如果您有任何問題或想要分享您的觀點,請隨時在評論區留言。

同時,不要忘記訂閱我的博客以獲取更多有趣的內容。在未來的文章中,我將繼續探討這個話題的不同方面,為您呈現更多深度和見解。

謝謝您的支持,期待與您在下一篇文章中再次相遇!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/21716.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/21716.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/21716.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

K210視覺識別模塊學習筆記2:固件的下載升級_官方數字識別例程導入方法

今日開始學習K210視覺識別模塊:固件的下載升級_官方數字識別例程導入方法 主要學習如何升級固件庫&#xff0c;在哪下載固件庫&#xff0c;以及如何在TF卡正確導入官方例程&#xff1a; 亞博智能的K210視覺識別模塊...... 固件庫版本: canmv_yahboom_v2.1.1.bin 本次最終目…

醫學數據屬于小樣本,或許源于資源不對等|羅小羅·說

小羅碎碎念 醫學數據屬于小樣本&#xff0c;或許源于資源不對等 今天這篇推文&#xff0c;源于一場對話。 我和他&#xff08;粉絲&#xff09;聊完以后&#xff0c;覺得心里總是壓了點什么東西&#xff0c;直到我寫完那篇關于醫學數據類別不平衡的文章&#xff0c;我才大致理…

SEO之關鍵詞擴展(一)

初創企業搭建網站的朋友看1號文章&#xff1b;想學習云計算&#xff0c;怎么入門看2號文章謝謝支持&#xff1a; 1、我給不會敲代碼又想搭建網站的人建議2、新手上云 確定了核心關鍵詞后&#xff0c;接下來就是進行關鍵詞擴展。對一個稍有規模的網站來說&#xff0c;研究幾十個…

Java設計模式 _行為型模式_狀態模式

一、狀態模式 1、狀態模式 狀態模式&#xff08;State Pattern&#xff09;是一種行為型模式。 它允許一個對象在其內部狀態改變時改變它的行為。狀態模式把所研究的對象的行為包裝在不同的狀態對象里&#xff0c;每一個狀態對象都屬于一個抽象狀態類的一個子類。狀態模式的意圖…

【Python Cookbook】S01E13 篩選序列中的元素

目錄 問題解決方案討論 問題 序列中包含一些數據&#xff0c;我們需要提取出其中的值或根據某些標準對序列做刪減。 解決方案 要篩選序列中的元素&#xff0c;通常最簡單的辦法是通過 列表推導式&#xff0c;例如&#xff1a; mylist [1, 4, -5, 10, -7, 2, 3, -1]print([…

JAVAEE之文件IO_數據流概念,字節流:InputStream、OutputStream,字符流:reader、writer,及實例代碼

什么是數據流 顧名思義&#xff0c;I 表示input&#xff0c;O 表示output&#xff0c;也就是輸入輸出流&#xff0c;主要是在程序與文件之間&#xff0c;用于傳輸數據的通道。既然要傳輸數據&#xff0c;那么我們需要理解文件和程序之間哪種方向的傳輸是輸入流&#xff0c;哪種…

SD-WAN供應商的類型及選擇指南

在企業加速數字化轉型的背景下&#xff0c;SD-WAN技術成為優化網絡性能和提升連接效率的重要方案&#xff0c;受到了廣泛關注。本文將介紹當前主要的SD-WAN供應商類型及其特點&#xff0c;并提供企業選擇合適供應商的建議。 目前&#xff0c;市場上的SD-WAN供應商主要分為兩類&…

操作系統(3) 處理機調度

目錄 一、處理機調度概述 1.基本準則 &#xff08;1&#xff09;CPU利用率 &#xff08;2&#xff09;系統吞吐量 &#xff08;3&#xff09;周轉時間 &#xff08;4&#xff09;等待時間 &#xff08;5&#xff09;響應時間 2.進程調度方式 &#xff08;1&#xff0…

現代密碼學-數字簽名

從消息認證碼到數字簽名 前面講到&#xff0c;消息認證碼無法防止否認&#xff0c;A,B之間共享密鑰計算出MAC,A,B都能計算出MAC,對于第三方C來說&#xff0c;他無法證明這個MAC是A計算的還是B計算的。 通過數字簽名解決問題。 A,B各自使用不同的密鑰-公鑰密碼&#xff0c;A用…

LeetCode刷題之HOT100之組合總和

2024/6/3 周一&#xff0c;工作日的第一天。昨晚夢到被導師說去實驗室不積極哈哈哈&#xff0c;風扇開到二級&#xff0c;早上被吹醒。買的書馬上快要到了。上午剛來準備刷題&#xff0c;結果去搞了一下數據庫sql&#xff0c;做的差不多了&#xff0c;還差點格式轉換就差不多出…

springboot打包筆記

文章目錄 多配置文件application.yml本地啟動參數替換profiles&#xff0c;還是要復制文件 項目有各種環境&#xff0c;例如&#xff1a;local&#xff0c;uat&#xff0c;prd等。 各種打包方式一定要熟練掌握。 做此筆記是因為做了那么多項目&#xff0c;也打了很多包&#xf…

QT中如何對引入的第三方庫進行翻譯

1、背景 在我們的程序中,可能會加載其他人寫的模塊,,該模塊是以庫的形式提供的,那么我們程序翻譯時,如何來對引入的第三方庫進行翻譯??? 2、方案 首先,第三方庫會有自己的翻譯文件,并且一般要給我們提供設置翻譯的接口, 例如下:第三方庫給我們暴露一個接口,我們…

軍用電源性能測試有哪些測試項目?需要遵循什么標準?

為了確保軍用電源在極端條件下能夠正常工作&#xff0c;必須對其進行一系列嚴格的性能測試。這些測試不僅包括效率、電壓調整率和負載調整率等基本參數的測試&#xff0c;還包括動態響應能力、絕緣電阻、耐壓測試、溫度系數以及高低溫循環等綜合性能的評估。 測試項目 效率 電壓…

spring 優雅替換bean

方案一&#xff1a;使用 Primary/Qualifier 注解&#xff08;優選&#xff09; 如果有多個相同類型的 Bean 存在&#xff0c;可以將想要優先使用的 Bean 加上 Primary 注解。 Qualifier和Primary注解的區別&#xff1a;Primary注解用于標記具有相同類型的多個實例中的主要實例…

MySQL -- 連接查詢

MySQL使用連接查詢&#xff08;JOIN&#xff09;是為了從多個相關表中獲取數據。連接查詢是一種強大且常用的操作&#xff0c;可以根據某些條件將兩張或多張表中的數據組合在一起&#xff0c;返回一個聯合結果集。 1.為什么使用連接查詢 數據規范化&#xff1a; 數據庫設計時通…

站點被篡改快照被劫持解決服務方法教程_一招制敵

站點被篡改快照被劫持解決服務方法教程_一招制敵 被篡改表現形式&#xff1a; 站點打不開或跳轉到別的網站。 攻擊者目的&#xff1a; 報復、勒索、賣防御產品&#xff08;如DDOS防御產品&#xff09;。 攻擊成本&#xff1a; 工具&#xff08;如VPN購買&#xff09;成本、人…

智能工廠生產設備實時監控技術的UI設計

智能工廠生產設備實時監控技術的UI設計

Flutter的Dart語法入門

文章目錄 前言1. 類型聲明2. 數據類型2.1 基本數據類型常量 2.2 String2.3 集合2.4 unicode 3. Dart函數特征3.1 可變參數列表和默認入參3.2 匿名函數3.3 typedef 4. Dart面向對象4.1 構造函數4.2 訪問權限4.3 類的繼承 參考資料附錄 前言 每個語言都有控制流語句就不寫測試代…

Go 語言的控制結構:條件與循環

Go 語言提供了豐富的控制結構&#xff0c;使得開發者可以編寫出具有復雜邏輯的程序。這些控制結構包括用于條件分支的 if-else 和 switch 語句&#xff0c;循環控制的 for 語句&#xff0c;以及用于控制循環執行流的 break 和 continue 關鍵字。此外&#xff0c;Go 語言還支持 …

約瑟夫游戲(編號+密碼)

編號為1、2、3、...、N的N個人按順時針方向圍坐一圈&#xff0c;每人持有一個密碼&#xff08;正整數&#xff09;。從指定編號為1的人開始&#xff0c;他的密碼為M的初始值&#xff0c;按順時針方向從1號自己開始順序報數&#xff0c;報到指定數M時停止報數&#xff0c;報M的人…