Paimon Sorting
#数据结构 #模拟
题目描述
Paimon just invents a new sorting algorithm which looks much like bubble sort, with a few differences. It
accepts a
1
1
1-indexed sequence
A
A
A of length n and sorts it. Its pseudo-code is shown below.
if you don’t believe this piece of algorithm can sort a sequence it will also be your task to prove it. Anyway
here comes the question:
Given an integer sequence
A
=
a
1
,
a
2
,
⋅
⋅
⋅
,
a
n
A = a_1, a_2, · · · , a_n
A=a1,a2,⋅⋅⋅,an of length n, for each of its prefix Ak of length k (that is, for
each
1
≤
k
≤
n
1 ≤ k ≤ n
1≤k≤n, consider the subsequence
A
k
=
a
1
,
a
2
,
⋅
⋅
⋅
,
a
k
)
,
A_k = a_1, a_2, · · · , a_k),
Ak=a1,a2,⋅⋅⋅,ak), count the number of swaps performed if
we call
S
O
R
T
(
A
k
)
SORT(A_k)
SORT(Ak).
输入格式
There are multiple test cases. The first line of the input contains an integer T indicating the number of test cases. For each test case:
The first line contains an integer
n
(
1
≤
n
≤
1
0
5
)
n (1 ≤ n ≤ 10^5)
n(1≤n≤105) indicating the length of the sequence.
The second line contains
n
n
n integers
a
1
,
a
2
,
⋅
⋅
⋅
,
a
n
(
1
≤
a
i
≤
n
)
a_1, a_2, · · · , a_n (1 ≤ a_i ≤ n)
a1,a2,⋅⋅⋅,an(1≤ai≤n) indicating the given sequence.
It’s guaranteed that the sum of
n
n
n of all test cases will not exceed
1
0
6
10^6
106
输出格式
For each test case output one line containing n integers
s
1
,
s
2
,
⋅
⋅
⋅
,
s
n
s_1, s_2, · · · , s_n
s1,s2,⋅⋅⋅,sn separated by a space, where
s
i
s_i
si is
the number of swaps performed if we call
S
O
R
T
(
A
i
)
SORT(A_i)
SORT(Ai).
Please, DO NOT output extra spaces at the end of each line or your solution may be considered incorrect!
样例 #1
样例输入 #1
3
5
2 3 2 1 5
3
1 2 3
1
1
样例输出 #1
0 2 3 5 7
0 2 4
0
解法
首先,暴力的做法 n 2 n^2 n2我们可以用来检验我们的程序是否正确,考虑每个前缀之间的规律,打个表可以发现:
1. 1. 1. 当新的数 a i = max ( a 1 , a 2 . . . , a i − 1 ) a_i = \max(a_1,a_2...,a_{i-1}) ai=max(a1,a2...,ai−1)时,可以发现此时的答案 r e s i = r e s i − 1 res_i =res_{i-1} resi=resi−1。
2. 2. 2. 当新的数 a i < max ( a 1 , a 2 , . . . , a i − 1 ) a_i < \max (a_1,a_2,...,a_{i-1}) ai<max(a1,a2,...,ai−1)时,此时答案 r e s i = r e s i − 1 + c n t res_i = res_{i-1}+cnt resi=resi−1+cnt,其中 c n t cnt cnt为 ( 1 , 2 , . . . , i − 1 ) (1,2,...,i-1) (1,2,...,i−1)中比 a i a_i ai大的数的个数的种类。
3. 3. 3. 当新的数 a i > max ( a i , a 2 , . . . , a i − 1 ) a_i > \max(a_i,a_2,...,a_{i-1}) ai>max(ai,a2,...,ai−1)时,我们序列中 ( 1 , 2 , . . . , i − 1 ) (1,2,...,i-1) (1,2,...,i−1)最大值第二次出现的的位置为 p o s pos pos,如果最大值只出现一次,那么 r e s i = r e s i − 1 + 2 res_i = res_{i-1}+2 resi=resi−1+2。 如果出现次数大于一次,那么 r e s i = r e s i − 1 + ( i − p o s + 2 ) res_i = res_{i-1}+(i-pos+2) resi=resi−1+(i−pos+2)。
因此,对于第 2 2 2种情况,我们可以使用主席树或者树状数组来维护,剩下两种情况就相对好维护一点了。
时间复杂度为 O ( n l o g 2 n ) O(nlog_2n) O(nlog2n)。
代码(主席树维护)
const int N = 2e6 + 10;
namespace Seg {
int tree[N];
void add(int l, int r, int v, int x, int val) {
if (l == r) {
tree[v] += val;
tree[v] = min(1ll, tree[v]);
tree[v] = max(tree[v], 0ll);
return;
}
else {
int mid = (l + r) >> 1;
if (x <= mid) add(l, mid, v << 1, x, val);
else add(mid + 1, r, v << 1 | 1, x, val);
tree[v] = tree[v << 1] + tree[v << 1 | 1];
}
}
int query(int v, int l, int r, int ql, int qr) {
if (l >= ql && r <= qr) {
return tree[v];
}
int sum = 0;
int mid = (l + r) >> 1;
if (ql <= mid)
sum += query(v << 1, l, mid, ql, qr);
if (qr >= mid + 1)
sum += query(v << 1 | 1, mid + 1, r, ql, qr);
return sum;
}
};
void solve() {
int n;
std::cin >> n;
std::vector<int>a(n + 1);
for (int i = 1; i <= n; ++i) {
std::cin >> a[i];
}
std::vector<int>res;
int mx, cnt=0, tmp = 0,last = 0;
for (int i = 1;i<=n; ++i) {
if (i == 1) {
res.push_back(last);
mx = a[i], cnt = 1;
}
else {
if (a[i] == mx) {
res.push_back(last);
cnt++;
if (cnt >= 2) tmp++;
}
else if (a[i] < mx) {
last = last + Seg:: query(1, 1, n, a[i] + 1, n);
res.push_back(last);
if (cnt >= 2) tmp++;
}
else {
last = last + 2 + tmp;
res.push_back(last);
mx = a[i];
tmp = 0;
cnt = 1;
}
}
Seg::add(1, n, 1, a[i], 1);
}
for (int i = 1; i <= n; i++) {
Seg::add(1, n, 1, a[i], -1);
if (i == n) {
cout << res[i - 1];
break;
}
cout << res[i - 1] << " ";
}
cout << '\n';
}
signed main() {
std::ios::sync_with_stdio(0);
std::cin.tie(0);
std::cout.tie(0);
int t = 1;
std::cin >> t;
while (t--) {
solve();
}
return 0;
}
代码(树状数组维护)
const int N = 1e5 + 10;
int n;
namespace BIT {
int tree[N];
void init() {
for (int i = 1; i <= n; ++i) {
tree[i] = 0;
}
}
inline int lowbit(int x) {
return x & (-x);
}
void add(int x, int val) {
while (x <= n) {
tree[x] += val;
x += lowbit(x);
}
}
int query(int x) {
int res = 0;
while (x > 0) {
res += tree[x];
x -= lowbit(x);
}
return res;
}
};
void solve() {
std::cin >> n;
std::vector<int>a(n + 1);
for (int i = 1; i <= n; ++i) {
std::cin >> a[i];
}
std::vector<int>res(n + 1);
res[1] = 0;
std::vector<bool>vis(n + 1);
vis[a[1]] = 1;
BIT::add(a[1], 1);
int maxx = a[1], cnt = 1, pos = -1;
for (int i = 2; i <= n; ++i) {
if (!vis[a[i]]) {
vis[a[i]] = 1;
BIT::add(a[i], 1);
}
if (a[i] == maxx) {
res[i] = res[i - 1];
cnt++;
if (cnt == 2) pos = i;
}
else if (a[i] < maxx) {
res[i] = res[i - 1] + BIT::query(maxx) - BIT::query(a[i]);
}
else {
if (pos == -1) res[i] = res[i - 1] + 2;
else {
res[i] = res[i - 1] + i - pos + 2;
}
maxx = a[i];
pos = -1;
cnt = 1;
}
}
for (int i = 1; i <= n; ++i) {
if (vis[a[i]]) {
vis[a[i]] = 0;
BIT::add(a[i], -1);
}
std::cout << res[i] << " \n"[i == n];
}
BIT::init();
}
signed main() {
std::ios::sync_with_stdio(0);
std::cin.tie(0);
std::cout.tie(0);
int t = 1;
std::cin >> t;
while (t--) {
solve();
}
return 0;
}