排排坐,吃果果,生果甜嗦嗦,大家笑呵呵。你一个,我一个,大的分给你,小的留给我,吃完果果唱支歌,大家乐和和。红星幼儿园的小朋友们排起了长长地队伍,准备吃果果。(出题人真 naive)
不过因为小朋友们的身高有所区别,排成的队伍高低错乱,极不美观。设第i个小朋友的身高为hi,我们定义一个序列的杂乱程度为:满足 hi>hj 的 (i, j) 数量。幼儿园阿姨每次会选出两个小朋友,交换他们的位置,请你帮忙计算出每次交换后,序列的杂乱程度。为方便幼儿园阿姨统计,在未进行任何交换操作时,你也应该输出该序列的杂乱程度。
第一行为一个正整数 n,表示小朋友的数量。
第二行包含 n 个由空格分隔的正整数 h1, h2, ..., hn,依次表示初始队列中小朋友的身高。
第三行为一个正整数 m,表示交换操作的次数。
以下 m 行每行包含两个正整数ai和bi,表示交换位置ai与位置bi的小朋友。
输出文件共 m 行,第 i 行一个正整数表示交换操作 i 结束后,序列的杂乱程度。
终于来一道简单题啦!(scx: ...)
这道题,数据规模看起来不是很大。
因为是一道逆序对的题目,所以,理所当然的先归并一下啦!(当然你想用树状数组也是可以滴)
归并排序的时候,有一个小技巧可以稍稍节省一点时间(只是减少常数罢了):
在拷贝两个子序列需要归并的时候,只需要复制左半边的,右半边在原地排序,可以证明,右半边的数在排到它之前不会被覆盖,所以时间减少了一半。然后询问的时候,设改变为 (l, r)
,如果 h[l] == h[r]
则输出原来的答案,否则,考虑在 l, r
之间的每个 i
,考虑 h[i] - h[l]
和 h[r] - h[i]
:
h[i] - h[l]
和 h[r] - h[i]
异号,则逆序对个数不变(h[i]
不在 (h[l], h[r])
之间)。h[i] - h[l]
和 h[r] - h[i]
同正,则逆序对个数加2(h[l] < h[i] < h[r]
)。h[i] - h[l]
和 h[r] - h[i]
同负,则逆序对个数减2(h[l] > h[i] > h[r]
)。h[i] - h[l]
和 h[r] - h[i]
一正一零,则逆序对个数加1。h[i] - h[l]
和 h[r] - h[i]
一负一零,则逆序对个数减1。可以看出,不管是哪一种情况,逆序对的变化量(带符号)就等于 sgn(h[i] - h[l]) + sgn(h[r] - h[i])
。
当然,i
不能取 r
,不然 (l, r)
会被算两次。
(scx: 时空复杂度会超限吗?)
可以看到,每个询问为的,所以,整个时间复杂度为的,又 n
到 20000, m
到 2000,因而不会 TLE,MLE 是肯定不会的。
#include <bits/stdc++.h>
#define sgn(i, j) ((a[i] > a[j]) - (a[i] < a[j])) // sgn(c[i] - c[j])
#define N 20034
using namespace std;
int n, q, i;
int l, r, ans = 0;
int a[N], buf[N], tmp[N];
int MergeSort(int L, int R){ // mergesort[L, R)
if(L + 1 == R) return L;
int M = L + R >> 1;
MergeSort(L, M);
MergeSort(M, R);
int i, j, k = L;
memcpy(tmp + L, buf + L, M - L << 2);
for(i = L, j = M; i < M || j < R; )
if(j >= R || (i < M && tmp[i] <= buf[j]))
buf[k++] = tmp[i++];
else{
buf[k++] = buf[j++];
ans += M - i;
}
return L;
}
int main(){
scanf("%d", &n);
for(i = 1; i <= n; i++)
scanf("%d", a + i);
memcpy(buf + 1, a + 1, n << 2);
MergeSort(1, n + 1);
printf("%d\n", ans);
for(scanf("%d", &q); q; q--){
scanf("%d%d", &l, &r);
if(l > r) swap(l, r);
if(a[l] == a[r]){
printf("%d\n", ans);
continue;
}
for(i = l; i < r; i++)
ans += sgn(i, l) + sgn(r, i);
swap(a[l], a[r]);
printf("%d\n", ans);
}
return 0;
}
坑1:询问的时候,数组应该为原来的数组,而不是排序后的数组,因此得拷贝一份去排序。
坑2:h[l] == h[r]
时,一定要输出原来的答案,否则会输出不够(导致我 WA 了一回)。