P8496 [NOI2022] 众数
绝对众数,联想到摩尔投票,支持 合并,单点删除。
维护序列,用平衡树即可。
最后用值域线段树合并,根据出现次数判断得出的是否是绝对众数即可。
平衡树 ,线段树合并均摊 ,故总时间复杂度为 。
具体实现见代码。
#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);
}
}
本文来自博客园,作者:蒟蒻orz,转载请注明原文链接:https://www.cnblogs.com/orzz/p/18121959
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· AI与.NET技术实操系列(六):基于图像分类模型对图像进行分类