P8496 [NOI2022] 众数

绝对众数,联想到摩尔投票,支持 O(1)\mathcal O(1) 合并,单点删除。

维护序列,用平衡树即可。

最后用值域线段树合并,根据出现次数判断得出的是否是绝对众数即可。

平衡树 O(nlogn)\mathcal O(n\log n),线段树合并均摊 O(nlogn)\mathcal O(n\log n),故总时间复杂度为 O(nlogn)\mathcal O(n\log n)

具体实现见代码。

#include <cstdio>
#include <random>

//#define int long long
typedef long long ll;

#define ha putchar(' ')
#define he putchar('\n')

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

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

using std::pair;

const int _ = 1e6 + 5;

int n, q, m, rt[_], t[_ >> 1];

std::mt19937 rnd(114514);

inline pair<int, int> calc(pair<int, int> x, pair<int, int> y) {
	if (x.first == y.first) return {x.first, x.second + y.second};
	if (x.second == y.second) return {0, 0};
	if (x.second > y.second) return {x.first, x.second - y.second};
	return {y.first, y.second - x.second};
}

struct fhq {
	int ls[_], rs[_], sz[_], val[_], cnt, rt[_];
	pair<int, int> tr[_];
	inline void pushup(int o) {
		sz[o] = sz[ls[o]] + sz[rs[o]] + 1;
		tr[o] = calc(calc(tr[ls[o]], {val[o], 1}), tr[rs[o]]);
	}
	void split(int o, int &x, int &y, int v) {
		if (!o) return x = y = 0, void();
		if (v >= sz[ls[o]] + 1) {
			x = o;
			split(rs[o], rs[x], y, v - sz[ls[o]] - 1);
		} else {
			y = o;
			split(ls[o], x, ls[y], v);
		}
		pushup(o);
	}
	int mge(int x, int y) {
		if (!x || !y) return x | y;
		if (rnd() % (sz[x] + sz[y]) < sz[x]) {
			rs[x] = mge(rs[x], y);
			pushup(x);
			return x;
		} else {
			ls[y] = mge(x, ls[y]);
			pushup(y);
			return y;
		}
	}
	inline void ins(int p, int x) {
		val[++cnt] = x, tr[cnt] = {x, 1}, sz[cnt] = 1;
		rt[p] = mge(rt[p], cnt);
	}
	inline int del(int p) {
		int x, y;
		split(rt[p], x, y, sz[rt[p]] - 1);
		rt[p] = x;
		return val[y];
	}
} T1;

struct sgt {
	int ls[_ * 60], rs[_ * 60], tr[_ * 60], cnt;
	void upd(int &o, int l, int r, int p, int v) {
		if (!o) o = ++cnt;
		if (l == r) return tr[o] += v, void();
		int mid = (l + r) >> 1;
		p <= mid ? upd(ls[o], l, mid, p, v) : upd(rs[o], mid + 1, r, p, v);
	}
	int mge(int x, int y, int l, int r) {
		if (!x || !y) return x | y;
		if (l == r) return tr[x] += tr[y], x;
		int mid = (l + r) >> 1;
		ls[x] = mge(ls[x], ls[y], l, mid), rs[x] = mge(rs[x], rs[y], mid + 1, r);
		return x;
	}
	int qry(int o, int l, int r, int p) {
		if (l == r) return tr[o];
		int mid = (l + r) >> 1;
		return p <= mid ? qry(ls[o], l, mid, p) : qry(rs[o], mid + 1, r, p);
	}
} T2;

inline void ins(int p, int x) {
	T1.ins(p, x);
	T2.upd(rt[p], 0, m, x, 1);
}

inline void del(int p) {
	int x = T1.del(p);
	T2.upd(rt[p], 0, m, x, -1);
}

inline void mge(int x, int y, int z) {
	rt[z] = T2.mge(rt[x], rt[y], 0, m);
	T1.rt[z] = T1.mge(T1.rt[x], T1.rt[y]);
}

signed main() {
	n = read(), q = read();
	m = n + q;
	for (int i = 1, c, x; i <= n; ++i) {
		c = read();
		while (c--) x = read(), ins(i, x);
	}
	pair<int, int> res;
	for (int i = 1, op, x, y, k; i <= q; ++i) {
		op = read();
		if (op == 1) x = read(), y = read(), ins(x, y);
		else if (op == 2) x = read(), del(x);
		else if (op == 3) {
			x = read(), y = 0, res = {0, 0}, k = 0;
			for (int j = 1; j <= x; ++j) {
				t[j] = read();
				res = calc(res, T1.tr[T1.rt[t[j]]]);
				k += T1.sz[T1.rt[t[j]]];
			}
			if (res.second == 0) {
				write(-1), he;
				continue;
			}
			if ((res.second << 1) > k) {
				write(res.first), he;
				continue;
			}
			for (int j = 1; j <= x; ++j) {
				y += T2.qry(rt[t[j]], 0, m, res.first);
				if ((y << 1) > k) break;
			}
			write(((y << 1) > k) ? res.first : -1), he;
		} else x = read(), y = read(), k = read(), mge(x, y, k);
	}
}
posted @   蒟蒻orz  阅读(4)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· AI与.NET技术实操系列(六):基于图像分类模型对图像进行分类
点击右上角即可分享
微信分享提示