[蓝桥杯 2019 省 A] 修改数组
并查集:如果有一种循环?递归的做法,导致思维上模拟出答案的这棵树高度很大,即抛出答案往往自底向上时因为高度问题超时,那么就是并查集
并查集还可用作频繁的计算,有点类似前缀和保存计算过程的思路,来加速运算,这种计算体现在,比如我是(1,2)(2,3)(3,…)已经计算了,现在有(1,1000),但我们可以通过(999,1000)来算答案
大概意思就是这样(上一个最近算式,本轮算式)=前缀和/并查集/…保留计算过程
并查集更用于自底向上一种答案树
题目描述
给定一个长度为 N N N 的数组 A = [ A 1 , A 2 , ⋯ A N ] A=[A_1,A_2, \cdots A_N] A=[A1,A2,⋯AN],数组中有可能有重复出现的整数。
现在小明要按以下方法将其修改为没有重复整数的数组。小明会依次修改 A 2 , A 3 , ⋯ , A N A_2,A_3, \cdots ,A_N A2,A3,⋯,AN。
当修改 A i A_i Ai 时,小明会检查 A i A_i Ai 是否在 A 1 A_1 A1 ∼ A i − 1 A_{i-1} Ai−1 中出现过。如果出现过,则小明会给 A i A_i Ai 加上 1 1 1;如果新的 A i A_i Ai 仍在之前出现过,小明会持续给 A i A_i Ai 加 1 1 1,直到 A i A_i Ai 没有在 A 1 A_1 A1 ∼ A i − 1 A_{i-1} Ai−1 中出现过。
当 A N A_N AN 也经过上述修改之后,显然 A A A 数组中就没有重复的整数了。
现在给定初始的 A A A 数组,请你计算出最终的 A A A 数组。
输入格式
第一行包含一个整数 N N N。
第二行包含 N N N 个整数 A 1 , A 2 , ⋯ , A N A_1,A_2, \cdots ,A_N A1,A2,⋯,AN。
输出格式
输出 N N N 个整数,依次是最终的 A 1 , A 2 , ⋯ , A N A_1,A_2, \cdots ,A_N A1,A2,⋯,AN。
样例 #1
样例输入 #1
5
2 1 1 3 4
样例输出 #1
2 1 3 4 5
提示
对于 80 % 80\% 80% 的评测用例, 1 ≤ N ≤ 10000 1 \le N \le 10000 1≤N≤10000。
对于所有评测用例, 1 ≤ N ≤ 1 0 5 1 \le N \le 10^5 1≤N≤105, 1 ≤ A i ≤ 1 0 6 1 \le A_i \le 10^6 1≤Ai≤106。
蓝桥杯 2019 年省赛 A 组 H 题。
1.哈希表做法
混分
#include<bits/stdc++.h>
using namespace std;
#define MAXN 1000000
int n;
bool bucket[MAXN+10];
int temp;
int main(){
cin>>n;
for(int i=1;i<=n;++i){
cin>>temp;
while(bucket[temp])++temp;
cout<<temp<<" ";
bucket[temp]=1;
}
}
如果有一种循环?递归的做法,导致思维上模拟出答案的这棵树高度很大,即抛出答案往往自底向上时因为高度问题超时,那么就是并查集
#include <bits/stdc++.h>
using namespace std;
#define Maxn 1000000
int bcj[Maxn+10];
void init(){//并查集初始化
for(int i=0;i<=Maxn;i++)bcj[i]=i;
}
int find(int x){//返回x所在树的根节点
if(x==bcj[x])return x;
else{
bcj[x] = find(bcj[x]);//父节点设为根节点
return bcj[x];//返回父节点
}
}
void merge(int i, int j){//前者并根进后者
bcj[find(i)] = find(j);
}
int main()
{
init();//初始化并查集,使每个结点所在树的根初始为自己
int n,temp;cin>>n;
for(int i=1;i<=n;++i){
cin>>temp;//得到结点
temp=find(temp);//将结点替换为所在树根节点
cout<<temp<<" ";//输出根节点
merge(temp,temp+1);//根节点与(根节点+1)结点并根
//↓下一次找已有值,就输出其+1,直至没有这个值为止
//实现方式:将其与其+1合并,使其+1为其的根节点
}
return 0;
}
2 1 1 3 4
2,取2所在树的根节点,得2,输出2,合并(2,3),使2所在树根节点并根进入3所在树根节点,意味着下一次找2,就得3
1,取1所在树的根节点,得1,输出1,合并(1,2)实质为(1,3),使1所在树根结点并根进入2所在树根节点,即3所在树根节点,意味着下一次找1,就得3
1,取1所在树的根节点,得3,输出3,合并(3,4),使3所在树的根节点并根进入4所在树根节点,下一次找3,得4,同时,下一次找1,2,得4
3,…,取3所在树的根节点,得4,输出4,合并(4,5).使下一次找1,2,3,4,得5
4,…,得5
所以有:2 1 3 4 5
这,就是并查集!