洛谷 P7110 晚秋绝诗

洛谷传送门

模拟赛时只写了 \(1, 3\) 事件在 \(2\) 后的分,赛后拓展一下这个做法就过了。一般。

首先考虑 \(O(nm)\) 暴力。注意到若一个极长连续段 \(l, l + 1, \ldots, r\) 被插了旗子,意味着 \(l - 1, l, \ldots, r, r + 1\) 构成一个等差数列,称这构成了一个

众所周知,一个等差数列只要知道其中任意两个数就能知道全部数,所以如果询问的 \(x\) 在一个知道了 \(\ge 2\) 个数的段里,那么就直接知道 \(x\) 了。

否则,\(x\) 所在的段必须由左边或右边最近的一个知道 \(\ge 2\) 个数的段推过来,具体就是设左边最近一个知道 \(\ge 2\) 个数的段(从左往右)编号为 \(i\)\(x\) 所在段编号为 \(j\),那么编号 \(i + 1, i + 2, \ldots, j\) 的段除左端点外都必须知道至少 \(1\) 个数,并且编号 \(i, i + 1, \ldots, j\) 的段必须连通(连通指段与段间有重叠部分)。右边类似。

还有一个 corner case,\(x\) 所在的段可以一个数也不知道,可以由左边推过来一个数,右边推过来一个数,那么这个段就知道了 \(2\) 个数。

注意到一个点最多在 \(2\) 个段(因为段与段之间只可能在端点重叠),所以每次都暴力这样 check 就是 \(O(nm)\) 的。

考虑 \(1, 3\) 事件在 \(2\) 后,那么我们可以先把所有段预处理出来,然后随便用个什么树状数组上二分或者线段树维护一个段左边第一个知道 \(\ge 2\) 个数的段,还有一个区间内是否所有段除左(或右)端点外至少知道 \(1\) 个数,还有一个段所在连通块的最左边(或最右边)的段。

拓展一下这个做法。现在问题是因为段时刻在变化,所以编号不固定。考虑线段树不是维护段,而是维护每个点,对于一个段 \((l, r)\),如果它存在 \(< 2\) 个知道的数,就把 \(l \sim r\)\(1\),那么找到左边第一个知道 \(\ge 2\) 个数的段就相当于找到左边第一个 \(= 0\) 的位置。这个随便线段树上二分做一下。

因为每个点所在段是 \(O(1)\) 个的,所以我们可以暴力 set 维护这些段。为了方便,我除了一个 set 维护这些段,还用一个 set 维护插旗的极长连续段。

我们还需要维护段之间的连通性。考虑一个段 \((l, r)\),我们把它覆盖的边都加 \(1\),即把 \(l \sim r - 1\)\(1\),那么找到一个段所在连通块最左边的段相当于找到一个点左边第一个 \(= 0\) 的位置。

更新段在线段树上的信息时,还需要维护区间有多少位置是否已知。

所以我们总共需要 \(1\) 个树状数组,\(4\) 个线段树,\(2\)set

总时间复杂度是 \(O(m \log n)\)

代码看起来很长,但思路清晰的话写起来还是很快的。

code
// Problem: P7110 晚秋绝诗
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P7110
// Memory Limit: 250 MB
// Time Limit: 2500 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;

const int maxn = 500100;

int n, m;

struct BIT {
	int c[maxn];
	
	inline void update(int x, int d) {
		for (int i = x; i < maxn; 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;
	}
	
	inline int query(int l, int r) {
		return max(0, query(r) - query(l - 1));
	}
} bit;

struct SGT {
	int a[maxn << 2], tag[maxn << 2];
	
	inline void pushup(int x) {
		a[x] = min(a[x << 1], a[x << 1 | 1]);
	}
	
	inline void pushdown(int x) {
		if (!tag[x]) {
			return;
		}
		a[x << 1] += tag[x];
		a[x << 1 | 1] += tag[x];
		tag[x << 1] += tag[x];
		tag[x << 1 | 1] += tag[x];
		tag[x] = 0;
	}
	
	void update(int rt, int l, int r, int ql, int qr, int x) {
		if (ql <= l && r <= qr) {
			a[rt] += x;
			tag[rt] += x;
			return;
		}
		pushdown(rt);
		int mid = (l + r) >> 1;
		if (ql <= mid) {
			update(rt << 1, l, mid, ql, qr, x);
		}
		if (qr > mid) {
			update(rt << 1 | 1, mid + 1, r, ql, qr, x);
		}
		pushup(rt);
	}
	
	int query(int rt, int l, int r, int ql, int qr) {
		if (ql > qr) {
			return 1e9;
		}
		if (ql <= l && r <= qr) {
			return a[rt];
		}
		pushdown(rt);
		int mid = (l + r) >> 1, res = 1e9;
		if (ql <= mid) {
			res = min(res, query(rt << 1, l, mid, ql, qr));
		}
		if (qr > mid) {
			res = min(res, query(rt << 1 | 1, mid + 1, r, ql, qr));
		}
		return res;
	}
	
	int findl(int rt, int l, int r) {
		if (l == r) {
			return l;
		}
		pushdown(rt);
		int mid = (l + r) >> 1;
		if (a[rt << 1] > 0) {
			return findl(rt << 1 | 1, mid + 1, r);
		} else {
			return findl(rt << 1, l, mid);
		}
	}
	
	int findr(int rt, int l, int r) {
		if (l == r) {
			return l;
		}
		pushdown(rt);
		int mid = (l + r) >> 1;
		if (a[rt << 1 | 1] > 0) {
			return findr(rt << 1, l, mid);
		} else {
			return findr(rt << 1 | 1, mid + 1, r);
		}
	}
	
	int findl(int rt, int l, int r, int ql, int qr) {
		if (a[rt] > 0 || ql > qr) {
			return -1;
		}
		if (ql <= l && r <= qr) {
			return findl(rt, l, r);
		}
		pushdown(rt);
		int mid = (l + r) >> 1;
		if (ql <= mid) {
			int t = findl(rt << 1, l, mid, ql, qr);
			if (t != -1) {
				return t;
			}
		}
		if (qr > mid) {
			int t = findl(rt << 1 | 1, mid + 1, r, ql, qr);
			if (t != -1) {
				return t;
			}
		}
		return -1;
	}
	
	int findr(int rt, int l, int r, int ql, int qr) {
		if (a[rt] > 0 || ql > qr) {
			return -1;
		}
		if (ql <= l && r <= qr) {
			return findr(rt, l, r);
		}
		pushdown(rt);
		int mid = (l + r) >> 1;
		if (qr > mid) {
			int t = findr(rt << 1 | 1, mid + 1, r, ql, qr);
			if (t != -1) {
				return t;
			}
		}
		if (ql <= mid) {
			int t = findr(rt << 1, l, mid, ql, qr);
			if (t != -1) {
				return t;
			}
		}
		return -1;
	}
} t1, t2, t3, t4;

set<pii> S, T;

int a[maxn], b[maxn];

inline vector<pii> getall(int i) {
	auto it = T.lower_bound(mkp(i, 0));
	vector<pii> res;
	if (it != T.end() && it->fst <= i && i <= it->scd) {
		res.pb(*it);
	}
	if (it != T.begin()) {
		--it;
		if (it->fst <= i && i <= it->scd) {
			res.pb(*it);
		}
	}
	return res;
}

inline void add(int l, int r) {
	int t = (bit.query(l, r) < 2);
	t1.update(1, 1, n, l, r, t);
	t = (bit.query(l + 1, r) >= 1);
	t2.update(1, 1, n, l, r, t);
	t = (bit.query(l, r - 1) >= 1);
	t3.update(1, 1, n, l, r, t);
}

inline void del(int l, int r) {
	int t = (bit.query(l, r) < 2);
	t1.update(1, 1, n, l, r, -t);
	t = (bit.query(l + 1, r) >= 1);
	t2.update(1, 1, n, l, r, -t);
	t = (bit.query(l, r - 1) >= 1);
	t3.update(1, 1, n, l, r, -t);
}

void solve() {
	scanf("%d%d", &n, &m);
	while (m--) {
		int op, x;
		scanf("%d%d", &op, &x);
		if (op == 1) {
			vector<pii> all = getall(x);
			for (pii p : all) {
				del(p.fst, p.scd);
			}
			bit.update(x, -a[x]);
			a[x] ^= 1;
			bit.update(x, a[x]);
			for (pii p : all) {
				add(p.fst, p.scd);
			}
		} else if (op == 2) {
			b[x] ^= 1;
			if (b[x]) {
				auto it = S.lower_bound(mkp(x, x));
				if (it != S.begin() && prev(it)->scd + 1 == x) {
					if (it != S.end() && it->fst - 1 == x) {
						auto jt = prev(it);
						int l = jt->fst, r = it->scd;
						del(it->fst - 1, it->scd + 1);
						del(jt->fst - 1, jt->scd + 1);
						T.erase(mkp(it->fst - 1, it->scd + 1));
						T.erase(mkp(jt->fst - 1, jt->scd + 1));
						t4.update(1, 1, n, it->fst - 1, it->scd, -1);
						t4.update(1, 1, n, jt->fst - 1, jt->scd, -1);
						S.erase(it);
						S.erase(jt);
						add(l - 1, r + 1);
						S.emplace(l, r);
						T.emplace(l - 1, r + 1);
						t4.update(1, 1, n, l - 1, r, 1);
					} else {
						--it;
						int l = it->fst, r = x;
						del(it->fst - 1, it->scd + 1);
						T.erase(mkp(it->fst - 1, it->scd + 1));
						t4.update(1, 1, n, it->fst - 1, it->scd, -1);
						S.erase(it);
						add(l - 1, r + 1);
						S.emplace(l, r);
						T.emplace(l - 1, r + 1);
						t4.update(1, 1, n, l - 1, r, 1);
					}
				} else {
					if (it != S.end() && it->fst - 1 == x) {
						int l = x, r = it->scd;
						del(it->fst - 1, it->scd + 1);
						T.erase(mkp(it->fst - 1, it->scd + 1));
						t4.update(1, 1, n, it->fst - 1, it->scd, -1);
						S.erase(it);
						add(l - 1, r + 1);
						S.emplace(l, r);
						T.emplace(l - 1, r + 1);
						t4.update(1, 1, n, l - 1, r, 1);
					} else {
						add(x - 1, x + 1);
						S.emplace(x, x);
						T.emplace(x - 1, x + 1);
						t4.update(1, 1, n, x - 1, x, 1);
					}
				}
			} else {
				auto it = --S.lower_bound(mkp(x, 1e9));
				int l = it->fst, r = it->scd;
				del(l - 1, r + 1);
				T.erase(mkp(l - 1, r + 1));
				t4.update(1, 1, n, l - 1, r, -1);
				S.erase(it);
				if (l < x) {
					add(l - 1, x);
					S.emplace(l, x - 1);
					T.emplace(l - 1, x);
					t4.update(1, 1, n, l - 1, x - 1, 1);
				}
				if (x < r) {
					add(x, r + 1);
					S.emplace(x + 1, r);
					T.emplace(x, r + 1);
					t4.update(1, 1, n, x, r, 1);
				}
			}
		} else {
			if (a[x]) {
				puts("1");
				continue;
			}
			bool fl = 0;
			vector<pii> all = getall(x);
			int l = max(1, t4.findr(1, 1, n, 1, x - 1) + 1);
			int r = t4.findl(1, 1, n, x, n);
			int p1 = t1.findr(1, 1, n, l, x);
			if (p1 != -1 && t2.query(1, 1, n, p1, x) > 0) {
				puts("1");
				continue;
			}
			int p2 = t1.findl(1, 1, n, x, r);
			if (p2 != -1 && t3.query(1, 1, n, x, p2) > 0) {
				puts("1");
				continue;
			}
			for (pii p : all) {
				if (p1 != -1 && p2 != -1 && t2.query(1, 1, n, p1, p.fst - 1) > 0 && t3.query(1, 1, n, p.scd + 1, p2) > 0) {
					fl = 1;
					break;
				}
			}
			printf("%d\n", fl);
		}
	}
}

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

posted @ 2023-12-18 18:32  zltzlt  阅读(50)  评论(0)    收藏  举报