题意
给出两个非严格单调递增序列,有修改和询问操作,对于询问操作,求出两个序列中取出两段组成新一段的第 k k k大的数。
思路
假设:X序列为X[xBeg…xEnd],而Y序列为Y[yBeg…yEnd]。
将序列X和Y都均分2段,即取X序列中间位置为xMid (xMid = xBeg+(xEnd-xBeg)/2),也同理取序列Y中间位置为yMid。
比较X[xMid]和Y[yMid]的大小,此时记录X左段和Y左段元素个数合计为halfLen,即halfLen = xMid-xBeg+yMid-yBeg+2。
-
当X[xMid] < Y[yMid]时,在合并的数组中,原X[xBeg…xMid]所有元素一定在Y[yMid]的左侧,
(1) 若k < halfLen,则此时第k大的元素一定不会大于Y[yMid]这个元素,故以后没有必要搜索 Y[yMid…yEnd]这些元素,可弃Y后半段数据。
此时只需递归的对X序列+Y序列的前半段,去搜索第k小的数。(2) 若k >= halfLen,则此时第k大的元素一定不会小于X[xMid]这个元素,故以后没有必要搜索 X[xBeg…xMid]这些元素,可弃X前半段数据。
此时只需递归的对X序列的后半段+Y序列,去搜索第 k-(xMid-xBeg+1)小的数。 -
当X[xMid] >= Y[yMid]时,在合并的数组中,原Y[yBeg…yMid]的所有元素一定在X[xMid]的左侧,
(1) 若k < halfLen,则此时第k大的元素一定不会大于X[xMid]这个元素,故以后没有必要搜索 X[xMid…xEnd]这些元素,可弃X后半段数据。
此时只需递归的对X序列的前半段+Y序列,去搜索第k小的数。(2) 若k >= halfLen,则此时第k大的元素一定不会小于Y[yMid]这个元素,故以后没有必要搜索 Y[yBeg…yMid]这些元素,可弃Y前半段数据。
此时只需递归的对X序列+Y序列的后半段,去搜索第 k-(yMid-yBeg+1)小的数。
以上转自blog
简单说,就是分治,之后会得出 4 4 4种情况,每种情况都能减去一半的序列。
代码
#include <cctype>
#include <cstdio>
#include <algorithm>
#define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++)
#define file(x) freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout)
int n, m;
int a[500001], b[500001], c[500001];
char buf[1 << 21], *p1 = buf, *p2 = buf;
inline int read() {
int res = 0, f = 0;
char ch = getchar();
while (!isdigit(ch)) {
if (ch == '-') f = 1;
ch = getchar();
}
while (isdigit (ch)) {
res = res * 10 + ch - 48;
ch = getchar();
}
return f ? -res : res;
}
int find(int aLeft, int aRight, int bLeft, int bRight, int k) {
if (aLeft > aRight) return b[bLeft + k - 1];
if (bLeft > bRight) return a[aLeft + k - 1];
int aMid = aRight + aLeft + 1 >> 1, bMid = bRight + bLeft + 1 >> 1;
int halfLen = aMid - aLeft + 1 + bMid - bLeft + 1;
if (a[aMid] < b[bMid]) {
if (k < halfLen) return find(aLeft, aRight, bLeft, bMid - 1, k);
else return find(aMid + 1, aRight, bLeft, bRight, k - (aMid - aLeft + 1));
} else {
if (k < halfLen) return find(aLeft, aMid - 1, bLeft, bRight, k);
else return find(aLeft, aRight, bMid + 1, bRight, k - (bMid - bLeft + 1));
}
}
int main() {
file(median);
n = read();
m = read();
for (register int i = 1; i <= n; i++)
a[i] = read();
for (register int i = 1; i <= n; i++)
b[i] = read();
for (register int op; m; m--) {
op = read();
if (op == 1) {
int x, y, z;
x = read();
y = read();
z = read();
if (x) b[y] = z;
else a[y] = z;
} else {
int l1, l2, r1, r2;
l1 = read();
r1 = read();
l2 = read();
r2 = read();
printf("%d\n", find(l1, r1, l2, r2, (r1 - l1 + 1 + r2 - l2 + 1) / 2 + 1));
}
}
}