01二分 [AGC006D] Median Pyramid Hard + P2824 [HEOI2016/TJOI2016] 排序

[AGC006D] Median Pyramid Hard

考虑对于一个长度为 2n + 1 的 01 序列 b 如何快速确定堆顶元素。
_ _ _ _ x
_ _ _ 0 x
_ _ 0 0 x
_ x 0 0 x
x x 0 0 x
容易得到,两个相同元素能够一直往上走,直到边界。
如果有两个相同元素出现在第 n 位,那答案显然为 b[n]。
那如果不在呢?
_ _ _ _ _ 0 0 x
_ _ _ _ 0 0 1 x
_ _ _ 0 0 1 0 x
_ _ 0 0 1 0 1 x
_ 0 0 1 0 1 0 x
0 0 1 0 1 0 1 x
得到结论,交替出现的 01 段能让两个相同元素斜向上平移。
由于离中心越近,越快能平移到中心。
因此离中心最近的两个相同元素即为答案。
最后特判没有相同元素的情况,也就是 01 交替出现,显然答案为 b[1]。

回到原题,考虑二分答案。
把原序列中 >= mid 的设为 1,< mid 的设为 0。
如果堆顶为 1 说明 ans >= mid,否则 < mid。

#include<bits/stdc++.h>
#define rep(i, a, b) for(int i = (a); i <= (b); ++ i)
#define per(i, a, b) for(int i = (a); i >= (b); -- i)
#define pb emplace_back
#define All(X) X.begin(), X.end()
using namespace std;
using ll = long long;
constexpr int N = 2e5 + 5;

int n, m, a[N], b[N];
int l, r, mid;

bool check(int v) {
	rep(i, 1, m) b[i] = a[i] >= v;
	rep(i, 0, n - 2) {
		if(b[n + i] == b[n + i + 1]) return b[n + i];
		if(b[n - i] == b[n - i - 1]) return b[n - i];
	}
	return b[1];
}

int main() {
	ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
	cin >> n; m = n * 2 - 1;
	rep(i, 1, m) cin >> a[i];
	l = 1, r = m;
	while(l < r) {
		if(check(mid = l + r + 1 >> 1)) l = mid;
		else r = mid - 1;
	}
	cout << l;
	return 0;
}

P2824 [HEOI2016/TJOI2016] 排序

题意:对一个长度为 n 的排列排 m 次序,问最终 p 位置是哪个数。

考虑对一个 01 序列进行一次排序需要多长时间。
令 cnt 等于 [l,r] 内 1 的个数。
对于升序操作,

  • 将 [l,r - cnt] 全改为 0。
  • 将 [r - cnt + 1, r] 全改为 1。

降序同理。
用线段树能做到 log n。

二分答案。
把原序列中 >= mid 的设为 1,< mid 的设为 0。
进行 m 次排序。
如果目标位置为 1 说明 ans >= mid,否则 < mid。
总复杂度 \(O(m\log^2n)\)

#include<bits/stdc++.h>
#define rep(i, a, b) for(int i = (a); i <= (b); ++ i)
#define per(i, a, b) for(int i = (a); i >= (b); -- i)
#define pb emplace_back
#define All(X) X.begin(), X.end()
using namespace std;
using ll = long long;
constexpr int N = 1e5 + 5;

struct Node {
	int op, l, r;
} q[N];

struct Seg {
	int v, tag, sz;
} t[N << 2];

int n, m, pos, a[N];

void pushup(int x) {
	t[x].v = t[x << 1].v + t[x << 1 | 1].v;
}

void pushdown(int x) {
	if(~t[x].tag) {
		int l = x << 1, r = l | 1;
		t[l].v = t[l].sz * t[x].tag, t[l].tag = t[x].tag;
		t[r].v = t[r].sz * t[x].tag, t[r].tag = t[x].tag;
		t[x].tag = -1;
	}
}

void build(int v, int x = 1, int l = 1, int r = n) {
	t[x] = {0, -1, r - l + 1};
	if(l == r) {
		t[x].v = a[l] >= v;
		return;
	}
	int mid = l + r >> 1;
	build(v, x << 1, l, mid);
	build(v, x << 1 | 1, mid + 1, r);
	pushup(x);
}

int query(int L, int R, int x = 1, int l = 1, int r = n) {
	if(L > R) return 0;
	if(L <= l && r <= R) return t[x].v;
	int mid = l + r >> 1, ret = 0;
	pushdown(x);
	if(mid >= L) ret += query(L, R, x << 1, l, mid);
	if(mid < R) ret += query(L, R, x << 1 | 1, mid + 1, r);
	return ret;
}

void modify(int L, int R, int v, int x = 1, int l = 1, int r = n) {
	if(L > R) return;
	if(L <= l && r <= R) return t[x].v = t[x].sz * (t[x].tag = v) , void();
	int mid = l + r >> 1;
	pushdown(x);
	if(mid >= L) modify(L, R, v, x << 1, l, mid);
	if(mid < R) modify(L, R, v, x << 1 | 1, mid + 1, r);
	pushup(x);
}

bool check(int v) {
	build(v);
	rep(i, 1, m) {
		auto [op, l, r] = q[i];
		int cnt = query(l, r);
		if(op) {
			modify(l, l + cnt - 1, 1);
			modify(l + cnt, r, 0);
		}
		else {
			modify(r - cnt + 1, r, 1);
			modify(l, r - cnt, 0);
		}
	}
	return query(pos, pos);
}

int main() {
	ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
	cin >> n >> m;
	rep(i, 1, n) cin >> a[i];
	rep(i, 1, m) cin >> q[i].op >> q[i].l >> q[i].r;
	cin >> pos;
	int l = 1, r = n;
	while(l < r) {
		int mid = l + r + 1 >> 1;
		if(check(mid)) l = mid;
		else r = mid - 1;
	}
	cout << l;
	return 0;
}
posted @ 2024-01-30 08:39  Lu_xZ  阅读(9)  评论(0编辑  收藏  举报