ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Codeforces Round #812 (Div. 2) E(并查集)

2022-08-07 23:03:04  阅读:174  来源: 互联网

标签:int siz 查集 交换 find merge 812 1010 Div


种类并查集:定义种类之间的关系来判断操作是否进行

题目大意:对于题目给出的一个矩阵,我们可以进行一种操作:swap(a[i][j],a[j][i])

使得矩阵可以变换为字典序最小的矩阵

 

思路:

  通过扫描整个矩阵,每次都判断a[i][j] 和 a[j][i]是否需要交换

  交换的前提就是: 对第i行/第j列操作,如果既对第 i 行又第 j 列进行操作等于没交换

  所以我们可以将 i 和 j定义为敌人,当 他们是敌人的时候,说明需要交换

  而他们是朋友的时候就说明无需交换

 

  这里就涉及到种类并查集了,我们定义一个2*n的数组,如果i 和 j 是敌人:

    merge( i , j+n );

    merge( i+n , j );

  这样在查询时如果find(i)>n说明i与另外一个元素有敌对关系,可以进行交换

  否则如果是朋友:

    merge( i , j );

    merge( i+n , j+n );

  find(i) <= n 说明他们为朋友关系,不可以交换 

 1 # include<iostream>
 2 # include<bits/stdc++.h>
 3 using namespace std;
 4 # define int long long
 5 # define endl "\n"
 6 const int N = 2e5 + 10;
 7 int a[1010][1010];
 8 int f[1010 << 1];
 9 vector<int> siz(1010 << 1);
10 int find(int x) {
11     if (f[x] == x) return x;
12     else return find(f[x]);
13 }
14 
15 void merge(int a, int b) {
16     int x = find(a);
17     int y = find(b);
18     if (x != y) {
19         if(siz[x]>siz[y]) swap(x,y);
20         f[x] = y;
21         siz[y] += siz[x];
22     }
23 }
24 void solve() {
25     int n;
26     cin >> n;
27     for (int i = 1; i <= n; ++i)
28         for (int j = 1; j <= n; ++j)
29             cin >> a[i][j];
30     for (int i = 1; i <= 2 * n; ++i) {
31         f[i] = i;
32         siz[i] = 1;
33     }
34     for (int i = 1; i <= n; ++i)
35         for (int j = i + 1; j <= n; ++j) {
36             if (a[i][j] > a[j][i]) {
37                 int x = find(i), y = find(j);
38                 if (x == y) continue;
39                 merge(i, j + n);
40                 merge(i + n, j);
41             } else if (a[i][j] < a[j][i]) {
42                 int x = find(i), y = find(j + n);
43                 if (x == y) continue;
44                 merge(i, j);
45                 merge(i + n, j + n);
46             }
47         }
48     for (int j = 1; j <= n; ++j) {
49         if (find(j) > n) continue;
50         for (int i = 1; i <= n; ++i) swap(a[i][j], a[j][i]);
51     }
52     for (int i = 1; i <= n; ++i) {
53         for (int j = 1; j <= n; ++j) {
54             cout << a[i][j] << " ";
55         }
56         cout << endl;
57     }
58 
59 }
60 int tt;
61 signed main() {
62     ios::sync_with_stdio(false);
63     cin.tie(0);
64     cout.tie(0);
65     cin >> tt;
66     while (tt--)solve();
67 
68 
69     return 0;
70 }
View Code 

需要注意的是,因为要求字典序最小,所以要求优先满足之前的关系,所以在每次维护关系的时候

需要先对之前的关系进行判断。

标签:int,siz,查集,交换,find,merge,812,1010,Div
来源: https://www.cnblogs.com/empty-y/p/16560182.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有