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;
}
posted @ 2018-12-21 11:52  King_George  阅读(243)  评论(0编辑  收藏  举报