ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

洛谷 P8496 [NOI2022] 众数 题解

2022-08-27 15:30:09  阅读:166  来源: 互联网

标签:rt head P8496 int 题解 ll tail NOI2022 siz


最近 7 年最水的 D1T1。

用权值线段树维护每个数出现的次数,链表维护序列。

操作 4 即合并两棵权值线段树、两个链表,操作 2 就是删除链表尾的元素并在权值线段树上修改。

显然,如果一个序列存在绝对众数,那么它必然等于这个序列的中位数。所以操作 3 就是询问 \(k\) 个序列整体的中位数,并检查这个数的出现次数。

考虑二分中位数,在 \(k\) 棵线段树上分别查询前缀和,再判断出现次数,然而时间复杂度是 \(O(n \log^2 n)\),可能无法通过。把二分中位数改成在 \(k\) 棵线段树上二分即可做到 \(O(n \log n)\)。

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int N = 1e6 + 3;
const int SIZE = N * 21;

int n, q, m;
int a[N], siz[N], head[N], tail[N], pre[N];

inline void insert(int i, int p) {
	pre[p] = tail[i];
	tail[i] = p;
	if (!siz[i]) head[i] = p;
	++siz[i];
}

inline void erase(int i) {
	tail[i] = pre[tail[i]];
	--siz[i];
	if (!siz[i]) head[i] = 0;
}

inline void link(int i, int j, int k) {
	head[k] = siz[i] ? head[i] : head[j];
	tail[k] = siz[j] ? tail[j] : tail[i];
	siz[k] = siz[i] + siz[j];
	if (head[j]) pre[head[j]] = tail[i];
}

int rt[N], ls[SIZE], rs[SIZE], tot;
ll cnt[SIZE];

void update(int &x, int k, int v, int l = 1, int r = n + q) {
	if (!x) x = ++tot;
	cnt[x] += v;
	if (l == r) return;
	int mid = (l + r) >> 1;
	if (k <= mid) update(ls[x], k, v, l, mid);
	else update(rs[x], k, v, mid + 1, r);
}

void merge(int &x, int &y, int l = 1, int r = n + q) {
	if (!x || !y) {
		x += y;
		return;
	}
	cnt[x] += cnt[y];
	if (l == r) return;
	int mid = (l + r) >> 1;
	merge(ls[x], ls[y], l, mid);
	merge(rs[x], rs[y], mid + 1, r);
}

ll query(int x, int k, int l = 1, int r = n + q) {
	if (!x) return 0;
	if (l == r) return cnt[x];
	int mid = (l + r) >> 1;
	if (k <= mid) return query(ls[x], k, l, mid);
	return query(rs[x], k, mid + 1, r);
}

int c[N], tmp[N], len;

int search(ll k, int l = 1, int r = n + q) {
	if (l == r) return l;
	int mid = (l + r) >> 1;
	ll sum = 0;
	for (int i = 1; i <= len; ++i)
		sum += cnt[ls[tmp[i]]];
	if (sum >= k) {
		for (int i = 1; i <= len; ++i)
			tmp[i] = ls[tmp[i]];
		return search(k, l, mid);
	} else {
		for (int i = 1; i <= len; ++i)
			tmp[i] = rs[tmp[i]];
		return search(k - sum, mid + 1, r);
	}
}

int main() {
	freopen("major.in", "r", stdin);
	freopen("major.out", "w", stdout);
	ios::sync_with_stdio(0);
	cin.tie(0);
	cin >> n >> q;
	for (int i = 1; i <= n; ++i) {
		int sz;
		cin >> sz;
		for (int j = 1; j <= sz; ++j) {
			int x;
			cin >> x;
			a[++m] = x;
			insert(i, m);
			update(rt[i], x, 1);
		}
	}
	for (int i = 1; i <= q; ++i) {
		int op, x, y, z;
		cin >> op;
		if (op == 1) {
			cin >> x >> y;
			a[++m] = y;
			insert(x, m);
			update(rt[x], y, 1); 
		} else if (op == 2) {
			cin >> x;
			update(rt[x], a[tail[x]], -1);
			erase(x);
		} else if (op == 3) {
			cin >> len;
			ll all = 0, sum = 0;
			for (int j = 1; j <= len; ++j) {
				cin >> c[j];
				tmp[j] = rt[c[j]];
				all += siz[c[j]];
			}
			int mid = search((all + 1) >> 1);
			for (int j = 1; j <= len; ++j)
				sum += query(rt[c[j]], mid);
			if (sum * 2 > all)
				cout << mid << '\n';
			else
				cout << "-1\n";
		} else {
			cin >> x >> y >> z;
			link(x, y, z);
			merge(rt[x], rt[y]);
			rt[z] = rt[x];
		}
	}
	return 0;
}

标签:rt,head,P8496,int,题解,ll,tail,NOI2022,siz
来源: https://www.cnblogs.com/2ha-maomao-2006/p/p8496-solution.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有