题目描述:
riba2534不小心穿越到了异世界,他必须从异世界出来,但是异世界有一个大魔王,非得让riba2534回答出他的问题才让他回到地球,问题是这样的:
大魔王用魔法变出来了n座大山,并且告诉你这n座大山的高度,现在他想问你,对于给出的每一座大山,这座大山之前有多少座大山比他的高度低。
riba2534非常惊慌失措,所以请你救救他!
输入描述:
多组测试数据 第一行给出一个整数n(1<=n<=100000)代表有n座大山
第二行给出来每座大山的高度h(1<=h<=1000000000),以空格作为分割。
输出描述:
对于每组数据,输出一行。 代表每座大山之前有多少座大山比这座大山低
思路
在这里就不介绍采用分治发的归并排序了,大家可以去这里看“点击”,刚开始做这题用了树状数组和离散化才把它A了,后来看了最优代码是用的是分治之后,打算写一篇采用分治的解法。(假定看这篇博客时各位已经掌握了归并排序)。
首先,由于排序后会改变它原先的位置(除了个别已经恰好排好了的),所以要记录他们原先在数组中的位置,也就是使用了一个结构体(由于只有两个信息,所以我使用了结构体模板pair)
const int N = 1e5+1;
pair<int , int>a[N], temp[N];
int num[N];
temp数组用于做中间变量,知道归并排序的都懂!
num数组储存结果
刚开始的时候我采用的是从小到大排序的算法,发现会有好多情况需要考虑,然后换成从大到小的方法就很容易理解了。
还是举个例子吧,来个理想化的
3 2 1 6 5 4
由于我们是按逆序排的,所以最后要合并的两个区间的是(3,2,1) 和(6,5,4)并且现在这两个区间内每个数的num值都为0,然后我们来进行合并操作。
void merga(int l, int mid, int r) {
int i = l, j = mid + 1, k = l;
while(i <= mid && j <= r) {
if(a[i].first >= a[j].first) { //first是值, second是每个数最开始时的位置。
temp[k++] = a[i++];
}
else {
num[a[j].second] += mid + 1 - i;
temp[k++] = a[j++];
}
}
while(i <= mid) temp[k++] = a[i++];
while(j <= r) temp[k++] = a[j++];
for (int i = l; i <= r; i++) {
a[i] = temp[i];
}
}
我来模拟一下他增加的操作,
3 < 6, num[3] (6在原数组中下表为3,别搞混了) += 2 + 1 - 0
3 < 5, num[4] += 2 + 1 - 0;
3 < 4, num[5] += 2 + 1 - 0;
最后合并。
也就是说它现在就是在找左边有多少个比右边的小,为什么是+=呢,实际上也很简单,如果我们把我刚刚的例子当成是另一个更长的数组的子串,那么再进行合并的时候就得加上上一次合并的结果。
给出完整代码:
#include<iostream>
#include<cstring>
using namespace std;
const int N = 1e5+1;
pair<int , int>a[N], temp[N];
int num[N];
void merga(int l, int mid, int r) {
int i = l, j = mid + 1, k = l;
while(i <= mid && j <= r) {
if(a[i].first >= a[j].first) {
temp[k++] = a[i++];
}
else {
num[a[j].second] += mid + 1 - i;
temp[k++] = a[j++];
}
}
while(i <= mid) temp[k++] = a[i++];
while(j <= r) temp[k++] = a[j++];
for (int i = l; i <= r; i++) {
a[i] = temp[i];
}
}
void merga_sort(int l, int r) {
if(l < r) {
int mid = (l + r) / 2;
merga_sort(l, mid);
merga_sort(mid + 1, r);
merga(l, mid, r);
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
int n;
while(cin >> n) {
memset(num, 0, sizeof(num));
for (int i = 0; i < n; i++) {
cin >> a[i].first;
a[i].second = i;
}
merga_sort(0, n-1);
for (int i = 0; i < n; i++) {
cout << num[i];
if(i < n - 1)
cout << " ";
else cout << endl;
}
}
}
萌新表达可以不太准确,有什么不懂的可以在下面评论。若有哪里不正确,请各位大佬指正。