P2824 [HEOI2016/TJOI2016] 排序

P2824 [HEOI2016/TJOI2016] 排序

首先,序列若干次操作一定有局部的子区间是有序的,但是直接维护区间内每个数的顺序的话,就会超时。所以我们可以用权值线段树来维护(维护的是每个数落在那个值上,区间个数)。

对于排序操作,操作区间一定为若干个有序区间全部或一部分(显然这种情况只能在区间端点处),我们可以用线段树合并将这些部分合并。对于有序区间的一部分,可以用线段树分裂。

那么问题来了,如何找到那些操作区间覆盖(或部分覆盖)到的区间呢?

可以用 set 维护若干个段 \([l,r]\),二分查找即可,剩下的操作就类似珂朵莉树了。

\(q\) 位置上的和就找到对应的线段树,线段树上二分即可。

代码写完再贴


写完了,调了半天。

#include <bits/stdc++.h>
#define ls son[p][0]
#define rs son[p][1]
using namespace std;

inline int read() {
	int x = 0, f = 1;
	char c = getchar();
	while (c < '0' || c > '9') f = c == '-' ? -1 : f, c = getchar();
	while (c >= '0' && c <= '9') x = (x<<3)+(x<<1)+(c^48), c = getchar();
	return x*f;
}

inline void write(int x) {
	if (x < 0) x = -x, putchar('-');
	if (x > 9) write(x/10);
	putchar('0'+x%10);
}

typedef set <int> :: iterator It;
const int N = 1e5+5, M = 6e6;
int n, m, q, cnt, tot, rt[N], op[M], gb[M], son[M][2], val[M];
set <int> s;

inline int newnode() { return tot ? gb[tot--] : ++cnt; }

inline void del(int p) { gb[++tot] = p; ls = rs = val[p] = 0; }

inline void modify(int &p, int l, int r, int x) {
	if (!p) p = newnode();
	val[p] = 1;
	if (l == r) return;
	int mid = l+r>>1;
	if (x <= mid) modify(ls, l, mid, x);
	else modify(rs, mid+1, r, x);
}

inline void merge(int &x, int y) {
	if (!x || !y) return (void)(x |= y);
	val[x] += val[y];
	merge(son[x][0], son[y][0]);
	merge(son[x][1], son[y][1]);
	del(y);
}

inline void split(int &x, int y, int k, int tag) {
	if (!y) return;
	x = newnode();
	int v = val[son[y][tag]];
	if (k > v) split(son[x][tag^1], son[y][tag^1], k-v, tag);
	else swap(son[x][tag^1], son[y][tag^1]);
	if (k < v) split(son[x][tag], son[y][tag], k, tag);
	val[x] = val[y]-k, val[y] = k;
}

inline int solve(int p, int l, int r) {
	if (l == r) return l;
	int mid = l+r>>1;
	return val[ls] ? solve(ls, l, mid) : solve(rs, mid+1, r);
}

inline It split_(int p) {
	It it = s.lower_bound(p);
	if (*it == p) return it;
	--it; split(rt[p], rt[*it], p-*it, op[p] = op[*it]);
	return s.insert(p).first;
}

inline void assign(int l, int r, int tag) {
	It end = split_(r+1), begin = split_(l);
	for (It it = ++begin; it != end; ++it) merge(rt[l], rt[*it]);
	s.erase(begin, end);
	op[l] = tag;
}

int main() {
	n = read(), m = read();
	s.insert(n+1);
	for (int i = 1; i <= n; ++i) s.insert(i), modify(rt[i], 1, n, read());
	while (m--) {
		int op = read(), l = read(), r = read();
		assign(l, r, op);
	}
	q = read();
	split_(q); split_(q+1);
	write(solve(rt[q], 1, n));
	return 0;
}

这题还有离线二分的解法?写了一下,解法看看题解吧。

#include <bits/stdc++.h>
#define ls p<<1
#define rs p<<1|1
using namespace std;

inline int read() {
	int x = 0, f = 1;
	char c = getchar();
	while (c < '0' || c > '9') f = c == '-' ? -1 : f, c = getchar();
	while (c >= '0' && c <= '9') x = (x<<3)+(x<<1)+(c^48), c = getchar();
	return x*f;
}

inline void write(int x) {
	if (x < 0) x = -x, putchar('-');
	if (x > 9) write(x/10);
	putchar('0'+x%10);
}

const int N = 1e5+5, M = N<<2;
int n, m, q, mid_, a[N], op[N], L[N], R[N], tag[M], sum[M];

inline void pushup(int p) { sum[p] = sum[ls]+sum[rs]; }

inline void pushdown(int p, int len) {
	if (tag[p] == -1) return;
	tag[ls] = tag[rs] = tag[p];
	if (tag[p]) sum[ls] = len-(len>>1), sum[rs] = len>>1;
	else sum[ls] = sum[rs] = 0;
	tag[p] = -1;
}

inline void build(int p, int l, int r) {
	tag[p] = -1;
	if (l == r) {
		sum[p] = a[l] >= mid_;
		return;
	}
	int mid = l+r>>1;
	build(ls, l, mid);
	build(rs, mid+1, r);
	pushup(p);
}

inline void modify(int p, int l, int r, int ql, int qr, int x) {
	if (qr < ql) return;
	if (ql <= l && r <= qr) {
		sum[p] = x*(r-l+1), tag[p] = x;
		return;
	}
	pushdown(p, r-l+1);
	int mid = l+r>>1;
	if (ql <= mid) modify(ls, l, mid, ql, qr, x);
	if (mid < qr) modify(rs, mid+1, r, ql, qr, x);
	pushup(p);
}

inline int query(int p, int l, int r, int ql, int qr) {
	if (ql <= l && r <= qr) return sum[p];
	pushdown(p, r-l+1);
	int mid = l+r>>1, sum = 0;
	if (ql <= mid) sum += query(ls, l, mid, ql, qr);
	if (mid < qr) sum += query(rs, mid+1, r, ql, qr);
	return sum;
}

inline int solve(int p, int l, int r, int x) {
	if (l == r) return sum[p];
	pushdown(p, r-l+1);
	int mid = l+r>>1;
	return x <= mid ? solve(ls, l, mid, x) : solve(rs, mid+1, r, x);
}

bool check() {
	build(1, 1, n);
	for (int i = 1; i <= m; ++i) {
		int cnt = query(1, 1, n, L[i], R[i]);
		if (op[i]) {
			modify(1, 1, n, L[i], L[i]+cnt-1, 1);
			modify(1, 1, n, L[i]+cnt, R[i], 0);
		}
		else {
			modify(1, 1, n, R[i]-cnt+1, R[i], 1);
			modify(1, 1, n, L[i], R[i]-cnt, 0);
		}
	}
	return solve(1, 1, n, q);
}

int main() {
	n = read(), m = read();
	for (int i = 1; i <= n; ++i) a[i] = read();
	for (int i = 1; i <= m; ++i) op[i] = read(), L[i] = read(), R[i] = read();
	q = read();
	int l = 1, r = n;
	while (l < r) {
		mid_ = l+r+1>>1;
		if (check()) l = mid_;
		else r = mid_-1;
	}
	write(l);
	return 0;
}
posted @ 2023-12-12 19:16  123wwm  阅读(21)  评论(0)    收藏  举报