洛谷 P9061 [Ynoi2002] Optimal Ordered Problem Solver

发布时间 2024-01-02 22:17:50作者: zltzlt

洛谷传送门

QOJ 传送门

考虑操作了若干次,所有点一定分布在一个自左上到右下的阶梯上或者在这个阶梯的右(上)侧。此处借用 H_W_Y 的一张图

考虑如何计算答案。对于一次询问 \((X, Y)\),如果它在阶梯左下方不用管它,否则考虑容斥,答案即为 \(x \ge X, y \ge Y\) 的点数,加上询问时不在阶梯上且 \(x \le X\) 的点数,加上询问时不在阶梯上且 \(y \le Y\) 的点数,加上阶梯上的所有点数,再加上阶梯在 \((X, Y)\) 左下方的点数。

不难发现这样计算会导致所求的被统计了 \(2\) 次,不为所求的被统计了 \(1\) 次。所以再减去总点数 \(n\) 就是答案。

发现 \(x \ge X, y \ge Y\) 的点数与时间维无关,因此是二维数点;若能处理出每个点进入阶梯的时刻(不难发现这个也是二维数点),那么询问时 \(x \le X\)\(y \le Y\) 的点数也是二维数点。

剩下的问题是维护阶梯。发现阶梯上的点是随着 \(x\) 不降 \(y\) 也不增的。可以考虑直接上 FHQ Treap 维护。这样查询阶梯在 \((X, Y)\) 左下方的点数,就直接 split 出对应的部分,答案就是这部分的 size。

每次操作可能会把阶梯某一部分向右或向上挪一点。可以直接打标记维护。

还要支持在固定时刻插入一个点(前面我们已经预处理出每个点进入阶梯的时间了)。这个操作 FHQ Treap 也支持。

所以总时间复杂度是 \(O(n \log n)\)。但是因为使用 FHQ Treap 常数巨大。接下来就是卡常了。

这是一份在 QOJ 能过但在洛谷过不了的代码
// Problem: P9061 [Ynoi2002] Optimal Ordered Problem Solver
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P9061
// Memory Limit: 512 MB
// Time Limit: 4000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>
#define pb emplace_back
#define fst first
#define scd second
#define mkp make_pair
#define mems(a, x) memset((a), (x), sizeof(a))

using namespace std;
typedef long long ll;
typedef double db;
typedef unsigned long long ull;
typedef long double ldb;
typedef pair<int, int> pii;

namespace IO {
    char ibuf[1 << 20], *iS, *iT, obuf[1 << 20], *oS = obuf;
#define writesp(x) write(x), pc(' ')
#define writeln(x) write(x), pc('\n')
#define gh() (iS == iT ? iT = (iS = ibuf) + fread(ibuf, 1, 1 << 20, stdin), (iS == iT ? EOF : *iS++) : *iS++)
	template<typename T = int>
    inline T read() {
        char ch = gh();
        T x = 0;
        bool t = 0;
        while (ch < '0' || ch > '9') t |= ch == '-', ch = gh();
        while (ch >= '0' && ch <= '9') x = (x << 1) + (x << 3) + (ch ^ 48), ch = gh();
        return t ? ~(x - 1) : x;
    }
    inline void flush () {
    	fwrite(obuf, 1, oS - obuf, stdout), oS = obuf;
	}
    inline void pc (char ch) {
    	if (oS == obuf + (1 << 20)) flush(); 
    	*oS++ = ch;
	}
	template<typename _Tp>
    inline void write (_Tp x) {
    	static char stk[64], *tp = stk;
    	if (x < 0) x = ~(x - 1), pc('-');
		do *tp++ = x % 10, x /= 10;
		while (x);
		while (tp != stk) pc((*--tp) | 48);
    }
}

using IO::read;
using IO::write;
using IO::pc;
using IO::flush;

const int maxn = 1000100;

int n, m, ans[maxn], head[maxn], len, val[maxn], nxt[maxn];
pii a[maxn];
mt19937 rnd(chrono::steady_clock::now().time_since_epoch().count());

inline void add(int x, int y) {
	val[++len] = y;
	nxt[len] = head[x];
	head[x] = len;
}

struct node {
	int o, x, y, qx, qy, id;
} qq[maxn];

struct {
	int c[maxn];
	
	inline void init() {
		mems(c, 0);
	}
	
	inline void update(int x, int d) {
		for (int i = x; i <= n; i += (i & (-i))) {
			c[i] += d;
		}
	}
	
	inline int query(int x) {
		int res = 0;
		for (int i = x; i; i -= (i & (-i))) {
			res += c[i];
		}
		return res;
	}
} t1, t2;

struct {
	int c[maxn];
	
	inline void init() {
		mems(c, 0x3f);
	}
	
	inline void update(int x, int d) {
		for (int i = x; i; i -= (i & (-i))) {
			c[i] = min(c[i], d);
		}
	}
	
	inline int query(int x) {
		int res = 2e9;
		for (int i = x; i <= n; i += (i & (-i))) {
			res = min(res, c[i]);
		}
		return res;
	}
} t3;

struct {
	int c[maxn];
	
	inline void init() {
		mems(c, -0x3f);
	}
	
	inline void update(int x, int d) {
		for (int i = x; i; i -= (i & (-i))) {
			c[i] = max(c[i], d);
		}
	}
	
	inline int query(int x) {
		int res = -2e9;
		for (int i = x; i <= n; i += (i & (-i))) {
			res = max(res, c[i]);
		}
		return res;
	}
} t4;

int rt, nt;

struct wwh {
	int p, ls, rs, x, y, sz, tx, ty;
} b[maxn];

inline void pushup(int x) {
	b[x].sz = b[b[x].ls].sz + b[b[x].rs].sz + 1;
}

inline void pushdown(int x) {
	int &tx = b[x].tx, &ty = b[x].ty, l = b[x].ls, r = b[x].rs;
	wwh &L = b[l], &R = b[r];
	if (tx != -1) {
		if (l) {
			L.x = L.tx = tx;
		}
		if (r) {
			R.x = R.tx = tx;
		}
		tx = -1;
	}
	if (ty != -1) {
		if (l) {
			L.y = L.ty = ty;
		}
		if (r) {
			R.y = R.ty = ty;
		}
		ty = -1;
	}
}

// x <= k, x > k
void splitx(int u, int k, int &x, int &y) {
	if (!u) {
		x = y = 0;
		return;
	}
	pushdown(u);
	if (b[u].x <= k) {
		x = u;
		splitx(b[u].rs, k, b[u].rs, y);
	} else {
		y = u;
		splitx(b[u].ls, k, x, b[u].ls);
	}
	pushup(u);
}

// y > k, y <= k
void splity(int u, int k, int &x, int &y) {
	if (!u) {
		x = y = 0;
		return;
	}
	pushdown(u);
	if (b[u].y > k) {
		x = u;
		splity(b[u].rs, k, b[u].rs, y);
	} else {
		y = u;
		splity(b[u].ls, k, x, b[u].ls);
	}
	pushup(u);
}

// x <= kx, y >= ky
void split(int u, int kx, int ky, int &x, int &y) {
	if (!u) {
		x = y = 0;
		return;
	}
	pushdown(u);
	if (b[u].x < kx || (b[u].x == kx && b[u].y >= ky)) {
		x = u;
		split(b[u].rs, kx, ky, b[u].rs, y);
	} else {
		y = u;
		split(b[u].ls, kx, ky, x, b[u].ls);
	}
	pushup(u);
}

int merge(int x, int y) {
	if (!x || !y) {
		return x | y;
	}
	if (b[x].p < b[y].p) {
		pushdown(x);
		b[x].rs = merge(b[x].rs, y);
		pushup(x);
		return x;
	} else {
		pushdown(y);
		b[y].ls = merge(x, b[y].ls);
		pushup(y);
		return y;
	}
}

inline int newnode(int x, int y) {
	int u = ++nt;
	b[u].x = x;
	b[u].y = y;
	b[u].sz = 1;
	b[u].p = rnd();
	b[u].tx = b[u].ty = -1;
	return u;
}

void solve() {
	n = read();
	m = read();
	for (int i = 1; i <= n; ++i) {
		a[i].fst = read();
		a[i].scd = read();
	}
	sort(a + 1, a + n + 1);
	// for (int i = 1; i <= n; ++i) {
		// printf("x, y: %d %d\n", a[i].fst, a[i].scd);
	// }
	for (int i = 1; i <= m; ++i) {
		qq[i].o = read();
		qq[i].x = read();
		qq[i].y = read();
		qq[i].qx = read();
		qq[i].qy = read();
		qq[i].id = i;
	}
	t3.init();
	t4.init();
	sort(qq + 1, qq + m + 1, [&](const node &a, const node &b) {
		return a.qx > b.qx;
	});
	for (int i = 1, j = n; i <= m; ++i) {
		while (j && a[j].fst > qq[i].qx) {
			t1.update(a[j].scd, 1);
			--j;
		}
		ans[qq[i].id] = n - j - t1.query(qq[i].qy);
	}
	sort(qq + 1, qq + m + 1, [&](const node &a, const node &b) {
		return a.x > b.x;
	});
	t1.init();
	for (int i = n, j = 1; i; --i) {
		t1.update(a[i].fst, 1);
		t2.update(a[i].scd, 1);
		while (j <= m && qq[j].x >= a[i].fst) {
			t3.update(qq[j].y, qq[j].id);
			++j;
		}
		int t = t3.query(a[i].scd);
		if (t <= m) {
			// printf("i: %d %d\n", i, t);
			add(t, i);
		}
	}
	sort(qq + 1, qq + m + 1, [&](const node &a, const node &b) {
		return a.id < b.id;
	});
	for (int i = 1, x, y, z; i <= m; ++i) {
		if (t4.query(qq[i].x + 1) <= qq[i].y) {
			t4.update(qq[i].x, qq[i].y);
			splitx(rt, qq[i].x, x, z);
			splity(x, qq[i].y, x, y);
			if (y) {
				if (qq[i].o == 1) {
					b[y].y = b[y].ty = qq[i].y;
				} else {
					b[y].x = b[y].tx = qq[i].x;
				}
			}
			rt = merge(merge(x, y), z);
		}
		for (int _ = head[i]; _; _ = nxt[_]) {
			int j = val[_];
			int xx = a[j].fst, yy = a[j].scd;
			t1.update(xx, -1);
			t2.update(yy, -1);
			if (qq[i].o == 1) {
				yy = qq[i].y;
			} else {
				xx = qq[i].x;
			}
			split(rt, xx, yy, x, y);
			rt = merge(merge(x, newnode(xx, yy)), y);
		}
		if (t4.query(qq[i].qx + 1) > qq[i].qy) {
			ans[i] = 0;
		} else {
			ans[i] += t1.query(qq[i].qx) + t2.query(qq[i].qy) + b[rt].sz;
			splitx(rt, qq[i].qx, x, z);
			splity(x, qq[i].qy, x, y);
			// printf("sz[%d] = %d\n", y, b[y].sz);
			ans[i] += b[y].sz - n;
			rt = merge(merge(x, y), z);
		}
		writeln(ans[i]);
	}
}

int main() {
	int T = 1;
	// scanf("%d", &T);
	while (T--) {
		solve();
	}
	flush();
	return 0;
}

这是一份在洛谷能过的代码
// Problem: P9061 [Ynoi2002] Optimal Ordered Problem Solver
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P9061
// Memory Limit: 512 MB
// Time Limit: 4000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>
#define pb emplace_back
#define fst first
#define scd second
#define mkp make_pair
#define mems(a, x) memset((a), (x), sizeof(a))

using namespace std;
typedef long long ll;
typedef unsigned uint;
typedef double db;
typedef unsigned long long ull;
typedef long double ldb;
typedef pair<uint, uint> pii;

namespace IO {
    char ibuf[1 << 20], *iS, *iT, obuf[1 << 20], *oS = obuf;
#define writesp(x) write(x), pc(' ')
#define writeln(x) write(x), pc('\n')
#define gh() (iS == iT ? iT = (iS = ibuf) + fread(ibuf, 1, 1 << 20, stdin), (iS == iT ? EOF : *iS++) : *iS++)
	template<typename T = uint>
    inline T read() {
        char ch = gh();
        T x = 0;
        bool t = 0;
        while (ch < '0' || ch > '9') t |= ch == '-', ch = gh();
        while (ch >= '0' && ch <= '9') x = (x << 1) + (x << 3) + (ch ^ 48), ch = gh();
        return t ? ~(x - 1) : x;
    }
    inline void flush () {
    	fwrite(obuf, 1, oS - obuf, stdout), oS = obuf;
	}
    inline void pc (char ch) {
    	if (oS == obuf + (1 << 20)) flush(); 
    	*oS++ = ch;
	}
	template<typename _Tp>
    inline void write (_Tp x) {
    	static char stk[64], *tp = stk;
    	if (x < 0) x = ~(x - 1), pc('-');
		do *tp++ = x % 10, x /= 10;
		while (x);
		while (tp != stk) pc((*--tp) | 48);
    }
}

using IO::read;
using IO::write;
using IO::pc;
using IO::flush;

const uint maxn = 1000100;

uint n, m, ans[maxn], head[maxn], len, val[maxn], nxt[maxn];
pii a[maxn], c[maxn];
mt19937 rnd(time(NULL));

inline void add(uint x, uint y) {
	val[++len] = y;
	nxt[len] = head[x];
	head[x] = len;
}

struct node {
	uint o, x, y, qx, qy, id;
} qq[maxn], pp[maxn];

struct {
	uint c[maxn];
	
	inline void init() {
		mems(c, 0);
	}
	
	inline void update(const uint &x, const uint &d) {
		for (uint i = x; i <= n; i += (i & (-i))) {
			c[i] += d;
		}
	}
	
	inline uint query(const uint &x) {
		uint res = 0;
		for (uint i = x; i; i -= (i & (-i))) {
			res += c[i];
		}
		return res;
	}
} t1, t2;

struct {
	uint c[maxn];
	
	inline void init() {
		mems(c, 0x3f);
	}
	
	inline void update(const uint &x, const uint &d) {
		for (uint i = x; i; i -= (i & (-i))) {
			(c[i] > d ? c[i] = d : 0);
		}
	}
	
	inline uint query(const uint &x) {
		uint res = 2e9;
		for (uint i = x; i <= n; i += (i & (-i))) {
			(res > c[i] ? res = c[i] : 0);
		}
		return res;
	}
} t3;

struct {
	uint c[maxn];
	
	inline void update(const uint &x, const uint &d) {
		for (uint i = x; i; i -= (i & (-i))) {
			(c[i] < d ? c[i] = d : 0);
		}
	}
	
	inline uint query(const uint &x) {
		uint res = 0;
		for (uint i = x; i <= n; i += (i & (-i))) {
			(res < c[i] ? res = c[i] : 0);
		}
		return res;
	}
} t4;

uint rt, nt;

struct wwh {
	uint p, ls, rs, x, y, sz, tx, ty;
} b[maxn];

// x <= k, x > k
void splitx(uint u, const uint &k, uint &x, uint &y) {
	if (!u) {
		x = y = 0;
		return;
	}
	wwh &t = b[u];
	uint &tx = t.tx, &ty = t.ty, &l = t.ls, &r = t.rs;
	wwh &L = b[l], &R = b[r];
	if (tx) {
		if (l) {
			L.x = L.tx = tx;
		}
		if (r) {
			R.x = R.tx = tx;
		}
		tx = 0;
	}
	if (ty) {
		if (l) {
			L.y = L.ty = ty;
		}
		if (r) {
			R.y = R.ty = ty;
		}
		ty = 0;
	}
	if (t.x <= k) {
		x = u;
		splitx(t.rs, k, t.rs, y);
	} else {
		y = u;
		splitx(t.ls, k, x, t.ls);
	}
	t.sz = b[l].sz + b[r].sz + 1;
}

// y > k, y <= k
void splity(uint u, const uint &k, uint &x, uint &y) {
	if (!u) {
		x = y = 0;
		return;
	}
	wwh &t = b[u];
	uint &tx = t.tx, &ty = t.ty, &l = t.ls, &r = t.rs;
	wwh &L = b[l], &R = b[r];
	if (tx) {
		if (l) {
			L.x = L.tx = tx;
		}
		if (r) {
			R.x = R.tx = tx;
		}
		tx = 0;
	}
	if (ty) {
		if (l) {
			L.y = L.ty = ty;
		}
		if (r) {
			R.y = R.ty = ty;
		}
		ty = 0;
	}
	if (t.y > k) {
		x = u;
		splity(t.rs, k, t.rs, y);
	} else {
		y = u;
		splity(t.ls, k, x, t.ls);
	}
	t.sz = b[l].sz + b[r].sz + 1;
}

// x <= kx, y >= ky
void split(uint u, const uint &kx, const uint &ky, uint &x, uint &y) {
	if (!u) {
		x = y = 0;
		return;
	}
	wwh &t = b[u];
	uint &tx = t.tx, &ty = t.ty, &l = t.ls, &r = t.rs;
	wwh &L = b[l], &R = b[r];
	if (tx) {
		if (l) {
			L.x = L.tx = tx;
		}
		if (r) {
			R.x = R.tx = tx;
		}
		tx = 0;
	}
	if (ty) {
		if (l) {
			L.y = L.ty = ty;
		}
		if (r) {
			R.y = R.ty = ty;
		}
		ty = 0;
	}
	if (t.x < kx || (t.x == kx && t.y >= ky)) {
		x = u;
		split(t.rs, kx, ky, t.rs, y);
	} else {
		y = u;
		split(t.ls, kx, ky, x, t.ls);
	}
	t.sz = b[l].sz + b[r].sz + 1;
}

uint merge(const uint &x, const uint &y) {
	if (!x || !y) {
		return x | y;
	}
	if (b[x].p < b[y].p) {
		wwh &t = b[x];
		uint &tx = t.tx, &ty = t.ty, &l = t.ls, &r = t.rs;
		wwh &L = b[l], &R = b[r];
		if (tx) {
			if (l) {
				L.x = L.tx = tx;
			}
			if (r) {
				R.x = R.tx = tx;
			}
			tx = 0;
		}
		if (ty) {
			if (l) {
				L.y = L.ty = ty;
			}
			if (r) {
				R.y = R.ty = ty;
			}
			ty = 0;
		}
		t.rs = merge(t.rs, y);
		t.sz = b[l].sz + b[r].sz + 1;
		return x;
	} else {
		wwh &t = b[y];
		uint &tx = t.tx, &ty = t.ty, &l = t.ls, &r = t.rs;
		wwh &L = b[l], &R = b[r];
		if (tx) {
			if (l) {
				L.x = L.tx = tx;
			}
			if (r) {
				R.x = R.tx = tx;
			}
			tx = 0;
		}
		if (ty) {
			if (l) {
				L.y = L.ty = ty;
			}
			if (r) {
				R.y = R.ty = ty;
			}
			ty = 0;
		}
		t.ls = merge(x, t.ls);
		t.sz = b[l].sz + b[r].sz + 1;
		return y;
	}
}

inline uint newnode(const uint &x, const uint &y) {
	uint u = ++nt;
	b[u].x = x;
	b[u].y = y;
	b[u].sz = 1;
	b[u].p = rnd();
	return u;
}

void solve() {
	n = read();
	m = read();
	for (uint i = 1; i <= n; ++i) {
		a[i].fst = read();
		a[i].scd = read();
		add(a[i].fst, i);
		c[i] = a[i];
	}
	uint tot = 0;
	for (uint i = 1; i <= n; ++i) {
		for (uint _ = head[i]; _; _ = nxt[_]) {
			a[++tot] = c[val[_]];
		}
	}
	for (uint i = 1; i <= m; ++i) {
		qq[i].o = read();
		qq[i].x = read();
		qq[i].y = read();
		qq[i].qx = read();
		qq[i].qy = read();
		qq[i].id = i;
	}
	t3.init();
	len = 0;
	mems(head, 0);
	for (uint i = 1; i <= m; ++i) {
		pp[i] = qq[i];
		add(qq[i].qx, i);
	}
	tot = 0;
	for (uint i = n; i; --i) {
		for (uint _ = head[i]; _; _ = nxt[_]) {
			qq[++tot] = pp[val[_]];
		}
	}
	for (uint i = 1, j = n; i <= m; ++i) {
		while (j && a[j].fst > qq[i].qx) {
			t1.update(a[j].scd, 1);
			--j;
		}
		ans[qq[i].id] = n - j - t1.query(qq[i].qy);
	}
	len = 0;
	mems(head, 0);
	for (uint i = 1; i <= m; ++i) {
		pp[i] = qq[i];
		add(qq[i].x, i);
	}
	tot = 0;
	for (uint i = n; i; --i) {
		for (uint _ = head[i]; _; _ = nxt[_]) {
			qq[++tot] = pp[val[_]];
		}
	}
	len = 0;
	mems(head, 0);
	t1.init();
	for (uint i = n, j = 1; i; --i) {
		t1.update(a[i].fst, 1);
		t2.update(a[i].scd, 1);
		while (j <= m && qq[j].x >= a[i].fst) {
			t3.update(qq[j].y, qq[j].id);
			++j;
		}
		uint t = t3.query(a[i].scd);
		if (t <= m) {
			// printf("i: %d %d\n", i, t);
			add(t, i);
		}
	}
	for (uint i = 1; i <= m; ++i) {
		pp[qq[i].id] = qq[i];
	}
	for (uint i = 1; i <= m; ++i) {
		qq[i] = pp[i];
	}
	for (uint i = 1, x, y, z, X, Y; i <= m; ++i) {
		t4.update(qq[i].x, qq[i].y);
		splity(rt, qq[i].y, x, z);
		splitx(z, qq[i].x, y, z);
		if (y) {
			if (qq[i].o == 1) {
				b[y].y = b[y].ty = qq[i].y;
			} else {
				b[y].x = b[y].tx = qq[i].x;
			}
		}
		for (uint _ = head[i]; _; _ = nxt[_]) {
			uint j = val[_];
			uint xx = a[j].fst, yy = a[j].scd;
			t1.update(xx, -1);
			t2.update(yy, -1);
			if (qq[i].o == 1) {
				yy = qq[i].y;
			} else {
				xx = qq[i].x;
			}
			split(y, xx, yy, X, Y);
			y = merge(merge(X, newnode(xx, yy)), Y);
			// y = merge(X, merge(newnode(xx, yy), Y));
		}
		// rt = merge(merge(x, y), z);
		rt = merge(x, merge(y, z));
		if (t4.query(qq[i].qx + 1) > qq[i].qy) {
			ans[i] = 0;
		} else {
			ans[i] += t1.query(qq[i].qx) + t2.query(qq[i].qy) + b[rt].sz;
			splity(rt, qq[i].qy, x, z);
			splitx(z, qq[i].qx, y, z);
			// printf("sz[%d] = %d\n", y, b[y].sz);
			ans[i] += b[y].sz - n;
			// rt = merge(merge(x, y), z);
			rt = merge(x, merge(y, z));
		}
		writeln(ans[i]);
	}
}

int main() {
	int T = 1;
	// scanf("%d", &T);
	while (T--) {
		solve();
	}
	flush();
	return 0;
}