题目大意
给出一个数组a,对于数组中的每个数,找出大于等于这个数,且在这个数前边没有出现过的最小的数字;
例如 a = [ 2 , 3 , 4 , 1 , 1 , 1 ] a = [2, 3, 4, 1, 1, 1] a=[2,3,4,1,1,1], 那么答案 a = [ 2 , 3 , 4 , 1 , 5 , 6 ] a = [2, 3 ,4 ,1, 5, 6] a=[2,3,4,1,5,6]
题目思路
用set维护区间,set中区间的存放方式为 [ r , l ] [r,l] [r,l],这里我们给出具体的维护过程
a = [ 2 , 3 , 4 , 1 , 1 , 1 ] a = [2, 3, 4, 1, 1, 1] a=[2,3,4,1,1,1]
-
i = 1 , s e t = [ 2 , 2 ] i = 1,set = {[2, 2]} i=1,set=[2,2]
-
i = 2 , s e t = [ 2 , 2 ] , [ 3 , 3 ] i = 2,set = {[2, 2], [3, 3]} i=2,set=[2,2],[3,3]
-
i = 3 , s e t = [ 2 , 2 ] , [ 3 , 3 ] , [ 4 , 4 ] i = 3,set = {[2, 2],[3,3],[4,4]} i=3,set=[2,2],[3,3],[4,4]
-
i = 4 , s e t = [ 1 , 1 ] [ 2 , 2 ] , [ 3 , 3 ] , [ 4 , 4 ] i = 4,set = {[1,1][2, 2],[3,3],[4,4]} i=4,set=[1,1][2,2],[3,3],[4,4]
-
i = 5 , s e t = [ 2 , 1 ] [ 2 , 2 ] , [ 3 , 3 ] , [ 4 , 4 ] i = 5,set = {[2,1][2, 2],[3,3],[4,4]} i=5,set=[2,1][2,2],[3,3],[4,4]
- s e t = [ 3 , 1 ] , [ 3 , 3 ] , [ 4 , 4 ] set = {[3,1],[3,3],[4,4]} set=[3,1],[3,3],[4,4]
- s e t = [ 4 , 1 ] , [ 4 , 4 ] set = {[4,1],[4,4]} set=[4,1],[4,4]
- s e t = [ 5 , 1 ] set = {[5,1]} set=[5,1]
-
i = 6 , s e t = [ 5 , 1 ] , [ 1 , 1 ] i = 6,set = {[5,1],[1,1]} i=6,set=[5,1],[1,1]
- s e t = [ 6 , 1 ] set = {[6,1]} set=[6,1]
所以每个数的最终答案为最后合并完的区间后右区间的值
AC代码
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n;
cin >> n;
vector<int> a(n + 1, 0);
set<pair<int, int> > st;
for(int i = 1;i <= n;i++) {
cin >> a[i];
auto p = pair<int, int>(a[i], a[i]);
auto iter = st.lower_bound(pair<int, int>(a[i], 0));
if(iter == st.end()) {
st.insert(p);
}
else {
if(a[i] < (*iter).second) {
st.insert(p);
}
else {
while(next(iter) != st.end()) {
if((*next(iter)).second == (*iter).first + 1) {
auto it1 = next(iter), it2 = iter;
pair<int, int> p1 = pair<int, int>((*it1).first, (*it2).second);
st.erase(it1);
st.erase(it2);
st.insert(p1);
iter = st.lower_bound(p1);
}
else {
break;
}
}
a[i] = (*iter).first + 1;
auto it = *iter;
it.first += 1;
st.erase(iter);
st.insert(it);
iter = st.lower_bound(it);
}
}
}
for(int i = 1;i <= n;i++) cout << a[i] << ' ';cout << '\n';
return 0;
}
更女少的做法!
我们可以使用并查集来维护一段连续的数字,当当前数字被使用后,我们可以将当前值和下一个值进行合并,并且令这个连通块的祖先为这个联通块最大的数(同时也是当前的答案)
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
unordered_map<int, int> fa;
int find(int x) {
if(fa[x] == 0) fa[x] = x;
return fa[x] == x? x : fa[x] = find(fa[x]);
}
void merge(int x, int y) {
x = find(x), y = find(y);
if(x == y) return;
if(x > y) swap(x, y);
fa[x] = y;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n;
cin >> n;
vector<int> a(n + 1);
for(int i = 1;i <= n;i++) {
cin >> a[i];
a[i] = find(a[i]);
merge(a[i], a[i] + 1);
}
for(int i = 1;i <= n;i++) cout << a[i] << ' ';cout << '\n';
return 0;
}
不摆了,卷!