Educational Codeforces Round 14 D. Swaps in Permutation (并查集orDFS)

题目链接:http://codeforces.com/problemset/problem/691/D

给你n个数,各不相同,范围是1到n。然后是m行数a和b,表示下标为a的数和下标为b的数可以交换无数次。问你最后字典序最大的数列是什么。

将下面的a和b用并查集联系起来存到祖节点对应的数组中,然后从大到小排序数组,最后依次按照父节点的数组中的顺序输出。

也可以用dfs的方法解(略麻烦),形成一个环路的就在一个数组中...

 1 //并查集
 2 #include <bits/stdc++.h>
 3 using namespace std;
 4 const int N = 1e6 + 5;
 5 vector <int> ans[N];
 6 vector <int> root;
 7 int pos[N] , par[N] , a[N] , vis[N];
 8
 9 int Find(int n) {
10     if(n == par[n])
11         return n;
12     return par[n] = Find(par[n]);
13 }
14
15 int main()
16 {
17     int n , m , u , v;
18     scanf("%d %d" , &n , &m);
19     for(int i = 1 ; i <= n ; ++i) {
20         scanf("%d" , a + i);
21         par[i] = i;
22     }
23     while(m--) {
24         scanf("%d %d" , &u , &v);
25         u = Find(u) , v = Find(v);
26         if(u != v)
27             par[u] = v;
28     }
29     for(int i = 1 ; i <= n ; ++i) {
30         int u = Find(i);
31         ans[u].push_back(a[i]);
32         if(!vis[u]) {
33             root.push_back(u);
34             vis[u] = true;
35         }
36     }
37     for(int i = 0 ; i < root.size() ; ++i)
38         sort(ans[root[i]].rbegin() , ans[root[i]].rend());
39     for(int i = 1 ; i < n ; ++i)
40         printf("%d " , ans[Find(i)][pos[Find(i)]++]);
41     printf("%d\n" , ans[Find(n)][pos[Find(n)]]);
42     return 0;
43 }
 1 //dfs
 2 #include <bits/stdc++.h>
 3 using namespace std;
 4 const int N = 1e6 + 5;
 5 struct Edge {
 6     int next , to;
 7 }edge[N << 1];
 8 vector <int> ans[N];
 9 vector <int> Root;
10 int a[N] , head[N] , cnt , is[N] , pos[N] , believe[N];
11 bool vis[N];
12
13 inline void add(int u , int v) {
14     edge[cnt].next = head[u];
15     edge[cnt].to = v;
16     head[u] = cnt++;
17 }
18
19 void dfs(int root , int u , int par) {
20     vis[u] = true;
21     is[u] = root;
22     ans[root].push_back(a[u]);
23     for(int i = head[u] ; ~i ; i = edge[i].next) {
24         int v = edge[i].to;
25         if(v == par || vis[v])
26             continue;
27         dfs(root , v , u);
28     }
29 }
30
31 int main()
32 {
33     memset(head , -1 , sizeof(head));
34     int n , m , u , v;
35     scanf("%d %d" , &n , &m);
36     for(int i = 1 ; i <= n ; ++i)
37         scanf("%d" , a + i);
38     while(m--) {
39         scanf("%d %d" , &u , &v);
40         add(u , v);
41         add(v , u);
42     }
43     for(int i = 1 ; i <= n ; ++i) {
44         if(!vis[i]) {
45             Root.push_back(i);
46             believe[i] = Root.size() - 1;
47             dfs(i , i , -1);
48         }
49     }
50     for(int i = 0 ; i < Root.size() ; ++i) {
51         sort(ans[Root[i]].rbegin() , ans[Root[i]].rend());
52     }
53     for(int i = 1 ; i <= n ; ++i) {
54         printf("%d" , ans[ Root[believe[is[i]]] ][ pos[believe[is[i]]]++ ]);
55         if(i != n)
56             putchar(‘ ‘);
57         else
58             putchar(‘\n‘);
59     }
60     return 0;
61 }
时间: 2024-10-23 19:32:53

Educational Codeforces Round 14 D. Swaps in Permutation (并查集orDFS)的相关文章

Codeforces Round #423 (Div. 2) C 思维,并查集 或 线段树 D 树构造,水

Codeforces Round #423 (Div. 2, rated, based on VK Cup Finals) C. String Reconstruction   思维,并查集 或 线段树 题意:一个字符串被删除了,但给出 n条信息,要还原出可能的字典序最小的字符串.信息有:字符串ti,ki个位置xi,表明原本的字符串在xi位置是以字符串ti开头的. tags:惨遭 fst,一开始把所有字符串都存下来,排序做的,结果爆内存了.. 方法1: 考虑并查集,对于字符串 ti,在位置xi,

Educational Codeforces Round 14 - F (codeforces 691F)

题目链接:http://codeforces.com/problemset/problem/691/F 题目大意:给定n个数,再给m个询问,每个询问给一个p,求n个数中有多少对数的乘积≥p 数据范围:2≤n≤10^6, 1≤ai≤3*10^6,1≤m≤10^6, 1≤p≤3*10^6 解题思路:比赛的时候比较naive的思路是把n中的数字排序去了重之后,对于每个p,最多枚举√p步,就能得到答案.而这个naive的思路是O(p√p)的,结果T了. 后来百思不得其解,去看了官方的解答.感觉是一种很有

Codeforces Round #623 (Div. 2) D.Recommendations 并查集

ABC实在是没什么好说的,但是D题真的太妙了,详细的说一下吧 首先思路是对于a相等的分类,假设有n个,则肯定要把n-1个都增加,因为a都是相等的,所以肯定是增加t小的分类,也就是说每次都能处理一个分类,复杂度是O(n^2),这个思路很好写,优先队列随便搞一下就行了,但是题目中N = 2 * 1e5,n^2肯定是不行的,然后就是这个很巧妙的方法了,cf官方的题解我没看懂...有点尴尬,它也没给标程,但是cf的题解好像不是这个方法 看了网上用并查集的方法,首先以t为关键字从大到小排序,然后用并查集维

Educational Codeforces Round 71 (Rated for Div. 2) D - Number Of Permutations

原文链接:https://www.cnblogs.com/xwl3109377858/p/11405773.html Educational Codeforces Round 71 (Rated for Div. 2) D - Number Of Permutations You are given a sequence of n pairs of integers: (a1,b1),(a2,b2),…,(an,bn). This sequence is called bad if it is

Educational Codeforces Round 21 G. Anthem of Berland(dp+kmp)

题目链接:Educational Codeforces Round 21 G. Anthem of Berland 题意: 给你两个字符串,第一个字符串包含问号,问号可以变成任意字符串. 问你第一个字符串最多包含多少个第二个字符串. 题解: 考虑dp[i][j],表示当前考虑到第一个串的第i位,已经匹配到第二个字符串的第j位. 这样的话复杂度为26*n*m*O(fail). fail可以用kmp进行预处理,将26个字母全部处理出来,这样复杂度就变成了26*n*m. 状态转移看代码(就是一个kmp

Educational Codeforces Round 26 D. Round Subset(dp)

题目链接:Educational Codeforces Round 26 D. Round Subset 题意: 给你n个数,让你选其中的k个数,使得这k个数的乘积的末尾的0的个数最大. 题解: 显然,末尾乘积0的个数和因子2和因子5的个数有关. 然后考虑dp[i][j]表示选i个数,当前因子5的个数为j时,能得到因子2最多的为多少. 那么对于每个数,记录一下因子2和5的个数,做一些01背包就行了. 1 #include<bits/stdc++.h> 2 #define mst(a,b) me

Educational Codeforces Round 23 F. MEX Queries(线段树)

题目链接:Educational Codeforces Round 23 F. MEX Queries 题意: 一共有n个操作. 1.  将[l,r]区间的数标记为1. 2.  将[l,r]区间的数标记为0. 3.  将[l,r]区间取反. 对每个操作,输出标记为0的最小正整数. 题解: hash后,用线段树xjb标记一下就行了. 1 #include<bits/stdc++.h> 2 #define ls l,m,rt<<1 3 #define rs m+1,r,rt<&l

Educational Codeforces Round 23 D. Imbalanced Array(单调栈)

题目链接:Educational Codeforces Round 23 D. Imbalanced Array 题意: 给你n个数,定义一个区间的不平衡因子为该区间最大值-最小值. 然后问你这n个数所有的区间的不平衡因子和 题解: 对每一个数算贡献,a[i]的贡献为 当a[i]为最大值时的 a[i]*(i-l+1)*(r-i+1) - 当a[i]为最小值时的a[i]*(i-l+1)*(r-i+1). 计算a[i]的l和r时,用单调栈维护.具体看代码,模拟一下就知道了. 然后把所有的贡献加起来.

Educational Codeforces Round 25 F. String Compression(kmp+dp)

题目链接:Educational Codeforces Round 25 F. String Compression 题意: 给你一个字符串,让你压缩,问压缩后最小的长度是多少. 压缩的形式为x(...)x(...)  x表示(...)这个出现的次数. 题解: 考虑dp[i]表示前i个字符压缩后的最小长度. 转移方程解释看代码,这里要用到kmp来找最小的循环节. 当然还有一种找循环节的方式就是预处理lcp,然后通过枚举循环节的方式. 这里我用的kmp找的循环节.复杂度严格n2. 1 #inclu