【BZOJ2653】middle

【题目链接】

【思路要点】

  • 中位数相关,考虑二分答案。
  • 我们现在想要检验\(Mid\)是否能够作为中位数出现,令大于等于\(Mid\)的元素为1,其余元素为-1,我们希望求出一个左右端点都在给定范围内的区间,使得区间和最大,若这个区间和非负,那么\(Mid\)能够作为中位数出现,否则不能。
  • 这个问题等价于找到在给定范围内的左右端点,使得左端点到1的和最小,右端点到\(N\)的和最小。
  • 我们将序列中的所有元素从大到小排序,初始时,令所有元素为-1,按从大到小的顺序依次将-1改写为1。
  • 改写一个元素等价于对前/后缀和进行区间加操作,额外维护区间最小值即可回答询问。
  • 将上述过程可持久化,即可完成本题。
  • 时间复杂度\(O(NLogN+QLog^2N)\)。

【代码】

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 20005;
const int MAXP = 3e6 + 5;
const int INF = 1e9;
template <typename T> void chkmax(T &x, T y) {x = max(x, y); }
template <typename T> void chkmin(T &x, T y) {x = min(x, y); } 
template <typename T> void read(T &x) {
	x = 0; int f = 1;
	char c = getchar();
	for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
	for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
	x *= f;
}
template <typename T> void write(T x) {
	if (x < 0) x = -x, putchar('-');
	if (x > 9) write(x / 10);
	putchar(x % 10 + '0');
}
template <typename T> void writeln(T x) {
	write(x);
	puts("");
}
struct SegmentTree {
	struct Node {
		int lc, rc;
		int premin, pretag;
		int sufmin, suftag;
	} a[MAXP];
	int n, size;
	int build(int l, int r) {
		int ans = ++size, mid = (l + r) / 2;
		a[ans].premin = -r;
		a[ans].sufmin = -(n - l + 1);
		a[ans].pretag = 0;
		a[ans].suftag = 0;
		if (l == r) return ans;
		a[ans].lc = build(l, mid);
		a[ans].rc = build(mid + 1, r);
		return ans;
	}
	int init(int x) {
		n = x;
		return build(1, n);
	}
	void pushdown(int root) {
		if (a[root].pretag == 0 && a[root].suftag == 0) return;
		int lc = ++size;
		a[lc] = a[a[root].lc];
		a[lc].pretag += a[root].pretag;
		a[lc].premin += a[root].pretag;
		a[lc].suftag += a[root].suftag;
		a[lc].sufmin += a[root].suftag;
		a[root].lc = lc;
		int rc = ++size;
		a[rc] = a[a[root].rc];
		a[rc].pretag += a[root].pretag;
		a[rc].premin += a[root].pretag;
		a[rc].suftag += a[root].suftag;
		a[rc].sufmin += a[root].suftag;
		a[root].rc = rc;
		a[root].pretag = a[root].suftag = 0;
	}
	void update(int root) {
		a[root].premin = min(a[a[root].lc].premin, a[a[root].rc].premin);
		a[root].sufmin = min(a[a[root].lc].sufmin, a[a[root].rc].sufmin);
	}
	int preadd(int root, int l, int r, int ql, int qr) {
		int ans = ++size;
		a[ans] = a[root];
		if (l == ql && r == qr) {
			a[ans].pretag += 2;
			a[ans].premin += 2;
			return ans;
		}
		pushdown(root);
		a[ans] = a[root];
		int mid = (l + r) / 2;
		if (mid >= ql) a[ans].lc = preadd(a[root].lc, l, mid, ql, min(mid, qr));
		if (mid + 1 <= qr) a[ans].rc = preadd(a[root].rc, mid + 1, r, max(mid + 1, ql), qr);
		update(ans);
		return ans;
	}
	int sufadd(int root, int l, int r, int ql, int qr) {
		int ans = ++size;
		a[ans] = a[root];
		if (l == ql && r == qr) {
			a[ans].suftag += 2;
			a[ans].sufmin += 2;
			return ans;
		}
		pushdown(root);
		a[ans] = a[root];
		int mid = (l + r) / 2;
		if (mid >= ql) a[ans].lc = sufadd(a[root].lc, l, mid, ql, min(mid, qr));
		if (mid + 1 <= qr) a[ans].rc = sufadd(a[root].rc, mid + 1, r, max(mid + 1, ql), qr);
		update(ans);
		return ans;
	}
	int extend(int root, int pos) {
		int ans = preadd(root, 1, n, pos, n);
		ans = sufadd(ans, 1, n, 1, pos);
		return ans;
	}
	int querysuf(int root, int l, int r, int ql, int qr) {
		if (l == ql && r == qr) return a[root].sufmin;
		pushdown(root);
		int ans = INF, mid = (l + r) / 2;
		if (mid >= ql) chkmin(ans, querysuf(a[root].lc, l, mid, ql, min(mid, qr)));
		if (mid + 1 <= qr) chkmin(ans, querysuf(a[root].rc, mid + 1, r, max(mid + 1, ql), qr));
		return ans;
	}
	int querysuf(int root, int l, int r) {
		if (l == n) return 0;
		if (r == n) return min(querysuf(root, 1, n, l + 1, n), 0);
		else return querysuf(root, 1, n, l + 1, r + 1);
	}
	int querypre(int root, int l, int r, int ql, int qr) {
		if (l == ql && r == qr) return a[root].premin;
		pushdown(root);
		int ans = INF, mid = (l + r) / 2;
		if (mid >= ql) chkmin(ans, querypre(a[root].lc, l, mid, ql, min(mid, qr)));
		if (mid + 1 <= qr) chkmin(ans, querypre(a[root].rc, mid + 1, r, max(mid + 1, ql), qr));
		return ans;
	}
	int querypre(int root, int l, int r) {
		if (r == 1) return 0;
		if (l == 1) return min(querypre(root, 1, n, 1, r - 1), 0);
		else return querypre(root, 1, n, l - 1, r - 1);
	}
} ST;
struct info {int x, home; } p[MAXN];
int n, q, root[MAXN];
bool cmp(info a, info b) {
	return a.x > b.x;
}
int main() {
	read(n);
	for (int i = 1; i <= n; i++) {
		int x; read(x);
		p[i] = (info) {x, i};
	}
	sort(p + 1, p + n + 1, cmp);
	root[0] = ST.init(n);
	for (int i = 1; i <= n; i++)
		root[i] = ST.extend(root[i - 1], p[i].home);
	read(q);
	int lastans = 0;
	for (int i = 1; i <= q; i++) {
		int opt[4];
		for (int j = 0; j <= 3; j++)
			read(opt[j]), opt[j] = (opt[j] + lastans) % n + 1;
		sort(opt, opt + 4);
		int a = opt[0], b = opt[1];
		int c = opt[2], d = opt[3];
		int l = 1, r = n;
		while (l < r) {
			int mid = (l + r) / 2, tmp = mid - (n - mid);
			if (tmp - ST.querypre(root[mid], a, b) - ST.querysuf(root[mid], c, d) >= 0) r = mid;
			else l = mid + 1;
		}
		writeln(lastans = p[l].x);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_39972971/article/details/80487784