讲真这题属实没有想到用并查集,看到队里一位大佬直接10几行搞定,而我用二分要几十行,这里贴出两份代码,一份并查集,一份二分代码,
·· 首先我们用s数组来从尾到头来记录第一个大于 该第i个元素的 下标
·· 进行初始化,最尾一个元素必定为-1,所以赋值s[n]=n+1,a[n+1]=-1;
·· 用 t 来描述它后一位元素 如果大于那么a[i]的答案为a[t]
所以用s[i]=t来记录;
#include<iostream>
#include<algorithm>
#include<map>
#include<string>
#include<cstring>
using namespace std;
int a[100005];
int s[100005];
int main(){
int n; cin >> n;
for (int i = 1; i <= n; i++)cin >> a[i];
s[n] = n + 1;//初始化
a[n + 1] = -1;
for (int i = n - 1; i >= 1; i--) {
int t = i + 1;//答案下标 ,以后一位来找到 “根“
while (t <= n && a[i] >= a[t])t = s[t];//找到第一个大于a[i]的值
s[i] = t;
}
for (int i = 1; i <= n; i++)
cout << a[s[i]] << " ";
return 0;
}
下面是二分的 应该比较容易理解,就是这个二维的vector数组
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<string>
#include<cstring>
#include<cmath>
#include<set>
#include<map>
#include<vector>
using namespace std;
int a[100015];
vector<int>b[100005];
int main() {
//freopen("888.txt","r",stdin);
int n; cin >> n;
for (int i = 0; i < n; i++) {
cin >> a[i];
b[a[i]].push_back(i);
}
for (int i = 0; i < n; i++) {
int flag = 1;
int minn = 1e5;
for (int j = a[i] + 1; j <= 50; j++) {
if (b[j].size()) {
int l = 0, r = b[j].size()-1, mid;
while (l + 1< r) {
mid = (l + r) / 2;
if (b[j][mid] > i)r = mid;
else l = mid;
}
int num = i - b[j][l];//防止左侧的值也大于i
int num2 = b[j][r] - i;
if (num < 0) {
minn = min(b[j][l], minn);
flag = 0;
}
else if (num2 > 0) {
minn = min(b[j][r], minn);
flag = 0;
}
}
}
if (flag)
cout << "-1" << " ";
else
cout << a[minn] << " ";
}
return 0;
}
如果还有啥更好的方法,麻烦分享一下哦