uoj445
题意
交互题。
有长度为 \(n\) 的排列,\(a_0,\ a_1,\ ...,\ a_{n-1}\)。
求一个排列 \(p_0,\ p_1,\ ...,\ p_{n-1}\) 满足 \(a_{p_i}\ <\ a_{p_{i+1}}\)。
有函数 super_sort(int *p, int n, int *q)
,传入的 \(n\) 要满足 \(n\ \leq\ k\),\(k\) 给定。\(q\) 为对 \(p\) 的一个重排列,满足 \(a_{q_i}\ <\ a_{q_{i+1}}\)。
调用 super_sort()
的次数不能超过限制 \(L\)。
\(n\ =\ 2^{19},\ k\ =\ 16,\ L\ =\ 562000\).
做法1
用线段树来辅助排序,\(node[l...r]\) 表示区间 \([l,\ r]\) 中 \(a\) 最小的下标。每次取出 \(node[0...n-1]\) 然后将这个点删去,将这个点到根的路径update一下。
建树的时候连续的 \(k\) 个可以一起建,这样一次可以建 \(4\) 层。
update的时候,最深的 \(4\) 层可以用一开始建树的结果update,再往上的点直接将距离路径距离为 \(1\) 且不在路径上的点拉出来拍个序就行了,这样每次update只用 \(1\) 次 super_sort()
。
代码
#include <bits/stdc++.h>
#include "sort.h"
void sort(int id, int n, int k, int *a) {
if(id <= 2) {
using namespace std;
srand(time(0));
function<void(int, int, int *)> dq = [&](int l, int r, int *a) {
static const int maxn = 524288;
static int b[maxn], pool[16], side[maxn];
if(r - l + 1 <= k) return super_sort(a + l, r - l + 1, a + l);
int mid = l + r >> 1;
dq(l, mid, a);
dq(mid + 1, r, a);
int b1 = l, b2 = mid + 1, i1 = 0, i2 = 0, i = 0, len = r - l + 1, half_len = len >> 1;
if(rand() & 1) {
swap(b1, b2);
swap(i1, i2);
}
while(i < len) {
if(i2 == half_len) {
while(i < len) b[i++] = a[b1 + i1++];
break;
}
if(i1 == half_len) {
while(i < len) b[i++] = a[b2 + i2++];
break;
}
int j = 0, last1, last2;
for (int i = 0; i < (k >> 1); ++i) {
if(i1 + i == half_len) break;
side[last1 = pool[j++] = a[b1 + i1 + i]] = 1;
}
for (int i = 0; i < (k >> 1); ++i) {
if(i2 + i == half_len) break;
side[last2 = pool[j++] = a[b2 + i2 + i]] = 2;
}
super_sort(pool, j, pool);
for (int k = 0; k < j; ++k) {
b[i++] = pool[k];
if(side[pool[k]] == 1) ++i1;
else ++i2;
if(pool[k] == last1 || pool[k] == last2) break;
}
}
for (int i = 0; i < len; ++i) a[l + i] = b[i];
return;
};
dq(0, n - 1, a);
return;
}
static int b[1 << 20], pool[16], rnk[1 << 19], Rnk[1 << 19], L = -1, R;
memset(b, -1, sizeof(b[0]) * n * 2);
for (int i = 0; i < n; i += k) {
for (int j = 0; j < k; ++j) b[i + n + j] = pool[j] = i + j;
super_sort(pool, k, pool);
for (int j = 0; j < k; ++j) rnk[pool[j]] = Rnk[pool[j]] = j;
int rt;
for (int l = i + n >> 1, r = i + n + k - 1 >> 1; ; l >>= 1, r >>= 1) {
for (int u = l; u <= r; ++u) b[u] = (rnk[b[u << 1]] < rnk[b[(u << 1) | 1]] ? b[u << 1] : b[(u << 1) | 1]);
if(l == r) {
rt = l;
break;
}
}
if(!~L) L = rt;
R = rt;
}
for (L >>= 1, R >>= 1;; L >>= 1, R >>= 1) {
if(R - L + 1 <= k / 2) {
int k = 0;
for (int u = L; u <= R; ++u) pool[k++] = b[u << 1], pool[k++] = b[(u << 1) | 1];
super_sort(pool, k, pool);
for (int j = 0; j < k; ++j) rnk[pool[j]] = Rnk[pool[j]] = j;
for (int l = L, r = R; ; l >>= 1, r >>= 1) {
for (int u = l; u <= r; ++u) b[u] = (rnk[b[u << 1]] < rnk[b[(u << 1) | 1]] ? b[u << 1] : b[(u << 1) | 1]);
if(l == r) {
break;
}
}
break;
}
for (int l = L; l <= R; l += k / 2) {
int r = l + k / 2 - 1;
int k = 0;
for (int u = l; u <= r; ++u) pool[k++] = b[u << 1], pool[k++] = b[(u << 1) | 1];
super_sort(pool, k, pool);
for (int j = 0; j < k; ++j) rnk[pool[j]] = Rnk[pool[j]] = j;
for (int u = l; u <= r; ++u) b[u] = (rnk[b[u << 1]] < rnk[b[(u << 1) | 1]] ? b[u << 1] : b[(u << 1) | 1]);
}
}
for (int i = 0; i < n; ++i) {
a[i] = b[1];
int x = a[i] + n;
for (int _ = k; _; _ >>= 1, x >>= 1) {
b[x] = -1;
if(x < n) {
int l = x << 1, r = l | 1;
if(!~b[l]) b[x] = b[r];
else if(!~b[r]) b[x] = b[l];
else b[x] = (Rnk[b[l]] < Rnk[b[r]] ? b[l] : b[r]);
}
}
int k = 0, rem = x;
while(x) {
int l = x << 1, r = l | 1;
b[x] = -1;
if(~b[l]) pool[k++] = b[l];
if(~b[r]) pool[k++] = b[r];
x >>= 1;
}
std::sort(pool, pool + k);
k = std::unique(pool, pool + k) - pool;
if(k) super_sort(pool, k, pool);
for (int j = 0; j < k; ++j) rnk[pool[j]] = j;
for (int x = rem; x; x >>= 1) {
int l = x << 1, r = (x << 1) | 1;
if(!~b[l]) b[x] = b[r];
else if(!~b[r]) b[x] = b[l];
else b[x] = (rnk[b[l]] < rnk[b[r]] ? b[l] : b[r]);
}
}
return;
}