CF 643G Choosing Ads(线段树)
文章目录
题目描述
给定一个长度为 $n$ 的序列和一个整数 $p$
有 $m$ 个操作,操作要么是区间赋值,要么是询问区间内出现次数至少占 $p%$ 的数
输出询问的答案时,可以包含错的数,也可以重复输出,但对的数一定要在答案中,且输出的数的个数不超过 $\lfloor \frac{100}{p} \rfloor$
$n,m \le 1.5 \times 10^5$
$20 \le p \le 100$
简要做法
考虑一个弱化版的问题,如何求出区间绝对众数
维护当前的众数 $val$ 和其出现的次数 $cnt$,每次扫到一个新的数,假如 $=val$ 就 $cnt +1$,否则 $cnt - 1$
当 $cnt = 0$,则将 $val$ 替换为新的 $val$
拓展到 $k$ 个数的情况同样正确
复杂度 $O(nk^2logn)$
参考代码
#include <stdio.h>
#include <algorithm>
#include <memory.h>
#include <vector>
int read(int x = 0, int f = 0, char ch = getchar())
{
while ('0' > ch or ch > '9')
f = ch == '-', ch = getchar();
while ('0' <= ch and ch <= '9')
x = x * 10 + (ch ^ 48), ch = getchar();
return f ? -x : x;
}
const int N = 15e4 + 5;
int n, m, p;
struct Seg_Tree
{
#define ls (p << 1)
#define rs (p << 1 | 1)
#define mid ((l + r) >> 1)
struct Node
{
int num, tag, val[5], cnt[5];
Node operator=(Node x) { return num = x.num, tag = 0, memcpy(val, x.val, sizeof val), memcpy(cnt, x.cnt, sizeof cnt), *this; }
} t[N << 2];
Node friend operator+(Node x, Node y)
{
Node res = y;
for (int i = 0; i < x.num; i++)
{
bool flag = false;
for (int j = 0; j < res.num and !flag; j++)
if (x.val[i] == res.val[j])
res.cnt[j] += x.cnt[i], flag = true;
if (flag)
continue;
if (res.num < p)
{
res.val[res.num] = x.val[i], res.cnt[res.num++] = x.cnt[i];
continue;
}
int k = 0;
for (int j = 1; j < res.num; j++)
if (res.cnt[j] < res.cnt[k])
k = j;
if (x.cnt[i] < res.cnt[k])
for (int j = 0; j < res.num; j++)
res.cnt[j] -= x.cnt[i];
else
{
int tmp = res.cnt[k];
res.val[k] = x.val[i], res.cnt[k] = x.cnt[i];
for (int j = 0; j < res.num; j++)
res.cnt[j] -= tmp;
}
}
return res;
}
void maintain(int p, int len, int val) { t[p].num = 1, t[p].tag = t[p].val[0] = val, t[p].cnt[0] = len; }
void push_up(int p) { t[p] = t[ls] + t[rs]; }
void push_down(int p, int len)
{
if (t[p].tag)
maintain(ls, len - len / 2, t[p].tag), maintain(rs, len / 2, t[p].tag), t[p].tag = 0;
}
void build(int p, int l, int r)
{
if (l == r)
return t[p].val[0] = read(), t[p].cnt[0] = t[p].num = 1, void();
build(ls, l, mid), build(rs, mid + 1, r), push_up(p);
}
void modify(int p, int l, int r, int x, int y, int val)
{
if (l == x and r == y)
return maintain(p, r - l + 1, val), void();
push_down(p, r - l + 1);
if (x <= mid)
modify(ls, l, mid, x, std::min(mid, y), val);
if (mid < y)
modify(rs, mid + 1, r, std::max(mid + 1, x), y, val);
push_up(p);
}
Node query(int p, int l, int r, int x, int y)
{
if (l == x and r == y)
return t[p];
push_down(p, r - l + 1);
if (y <= mid)
return query(ls, l, mid, x, y);
else if (mid < x)
return query(rs, mid + 1, r, x, y);
else
return query(ls, l, mid, x, mid) + query(rs, mid + 1, r, mid + 1, y);
}
void getans(int l, int r)
{
Node ans = query(1, 1, n, l, r);
printf("%d ", ans.num);
for (int i = 0; i < ans.num; i++)
printf("%d ", ans.val[i]);
puts("");
}
} T;
int main()
{
n = read(), m = read(), p = 100 / read(), T.build(1, 1, n);
for (; m--;)
{
int opt = read(), l = read(), r = read();
if (opt == 1)
T.modify(1, 1, n, l, r, read());
else
T.getans(l, r);
}
return 0;
}