P6272 [湖北省队互测2014] 没有人的算术 题解

\(\text{P6272 [湖北省队互测2014] 没有人的算术 题解}\)

直接去按照题目给定的递归形式去维护显然是困难的。由于总形态的个数显然是 \(O(m)\) 级别,我们考虑设计一种方式使得可以表示出每种形态的权值然后互相比较。考虑直接在这些个状态上去维护权值表示大小关系,然后把每次单点修改和区间查询挂到线段树上去做是容易的。由于我们只需要维护大小关系,因此最直接的办法就是建一棵平衡树来维护大小关系,然后将大小关系用离散化后的权值直观地表示出来即可,具体地,我们可以给一个节点赋定一个区间 \([l,r]\),给这个节点本身赋值为 \(mid=\dfrac{l+r}2\),左右区间分别赋值为 \([l,mid],[mid,r]\)。然后我们插入的时候就在平衡树上用重定义的大小关系插入,这样一来就将权值离散化了出来。至于精度问题,直接用可以暴力维护的替罪羊树保证树高 \(\log n\) 且可以方便的重构值域来维护。

代码:

#include <bits/stdc++.h>
#define N 500005
using namespace std;
using ld = long double;
const ld shit = 0.75;
const ld inf = 1e9;
int n, m, rt;
ld vl[N];
struct BAS {
	int x, y;
	bool operator < (const BAS &a) const {
		return vl[x] < vl[a.x] || (vl[x] == vl[a.x] && vl[y] < vl[a.y]);
	}
	bool operator == (const BAS &a) const {
		return x == a.x && y == a.y;
	}
};
namespace SHIT {
	struct Node {
		int lc, rc, sm;
		BAS bas;
	} e[N];
	int tot;
	#define lc(i) e[i].lc
	#define rc(i) e[i].rc
	#define sm(i) e[i].sm
	#define vl(i) e[i].vl
	#define bas(i) e[i].bas
	void push_up(int p) {
		sm(p) = sm(lc(p)) + sm(rc(p)) + 1;
	}
	bool gotoshit(int p) {
		return (ld)max(sm(lc(p)), sm(rc(p))) > shit * sm(p);
	}
	int id[N], cp;
	void sve(int p) {
		if (!p) return;
		sve(lc(p));
		id[++cp] = p;
		sve(rc(p));
	}
	void build(int &p, int l, int r, ld ql, ld qr) {
		if (l > r) return p = 0, void();
		int mid = (l + r) >> 1;
		p = id[mid];
		ld qm = (ql + qr) * 0.5;
		vl[p] = qm;
		build(lc(p), l, mid - 1, ql, qm);
		build(rc(p), mid + 1, r, qm, qr);
		push_up(p);
	}
	void forashit(int &p, ld ql, ld qr) {
		cp = 0;
		sve(p);
		build(p, 1, cp, ql, qr);
	}
	int insert(int &p, ld ql, ld qr, BAS x) {
		ld qm = (ql + qr) * 0.5;
		if (!p) {
			p = ++tot;
			vl[p] = qm;
			e[p] = {0, 0, 1, x};
			return p;
		}
		int q = 0;
		if (bas(p) == x) ++sm(p), q = p;
		else if (x < bas(p)) q = insert(lc(p), ql, qm, x);
		else q = insert(rc(p), qm, qr, x);
		if (gotoshit(p)) forashit(p, ql, qr);
		return q;
	}
	#undef lc
	#undef rc
} 

int pos[N];
namespace FUCK {
	struct Node {
		int l, r;
		int mx, mp;
		Node() {
			l = r = mx = mp = 0;
		}
	} e[N << 2];
	#define l(i) e[i].l
	#define r(i) e[i].r
	#define mx(i) e[i].mx
	#define mp(i) e[i].mp
	#define lc (p << 1)
	#define rc (lc | 1)
	void push_up(Node &p, Node ls, Node rs) {
		if (vl[ls.mx] > vl[rs.mx]) p.mx = ls.mx, p.mp = ls.mp;
		else if (vl[rs.mx] > vl[ls.mx]) p.mx = rs.mx, p.mp = rs.mp;
		else p.mx = ls.mx, p.mp = min(ls.mp, rs.mp);
	}
	void build(int p, int l, int r) {
		l(p) = l, r(p) = r;
		if (l == r) return mx(p) = pos[l], mp(p) = l, void();
		int mid = (l + r) >> 1;
		build(lc, l, mid);
		build(rc, mid + 1, r);
		push_up(e[p], e[lc], e[rc]);
	}
	void update(int p, int x, int t) {
		if (l(p) == r(p)) return mx(p) = t, void();
		int mid = (l(p) + r(p)) >> 1;
		if (x <= mid) update(lc, x, t);
		else update(rc, x, t);
		push_up(e[p], e[lc], e[rc]);
	}
	Node query(int p, int l, int r) {
		if (l <= l(p) && r(p) <= r) return e[p];
		int mid = (l(p) + r(p)) >> 1;
		if (r <= mid) return query(lc, l, r);
		if (l > mid) return query(rc, l, r);
		Node ans;
		push_up(ans, query(lc, l, r), query(rc, l, r));
		return ans;
	}
}

int main() {
	ios::sync_with_stdio(0);
	cin.tie(0);
	cin >> n >> m;
	FUCK::build(1, 1, n);
	while (m--) {
		char c;
		int l, r;
		cin >> c >> l >> r;
		if (c == 'C') {
			int k;
			cin >> k;
			pos[k] = SHIT::insert(rt, 1, inf, {pos[l], pos[r]});
			FUCK::update(1, k, pos[k]);
		}
		else cout << FUCK::query(1, l, r).mp << "\n";
	}
	return 0;
}
posted @ 2025-03-11 21:57  长安19路  阅读(17)  评论(0)    收藏  举报