题意
给定一个长度为n的序列和一个常数p%,有三种操作:
- 区间加
- 区间赋值
- 输出所有区间内占比>=p%的所有元素。但是可以包含<=p%的元素。
n ≤ 1 0 5 , p > = 20 n\leq10^5,p>=20 n≤105,p>=20
分析
- 找一个最小的k使得 p % > 1 / k p\%>1/k p%>1/k。将限制放宽到占比>1/k,即出现次数大于 n / k 下 取 整 n/k下取整 n/k下取整
- 假如说我们要找一个占比>1/2的,可以不断取两个不同的数,到最后剩下的就是答案。
- 其实就是维护一个计数器的事。
- 那我们推广到k,也可以不断取k个不同的数,答案一定在最后剩下的k-1种数中。
- 正确性其实很显然,因为最多可以取 n / k n/k n/k下取整次。
- 注意到元素的加入顺序没所谓,使用线段树维护当前删完之后剩下的k-1种数,及其个数即可。
- k最多取到6,复杂度是 O ( n k log n ) O(nk \log n) O(nklogn)
#include <bits/stdc++.h>
#define mp make_pair
using namespace std;
const int N = 1.5e5 + 1000;
typedef pair<int,int> pii;
vector<pii> t[N * 4];
int n, m, p, a[N];
int no, dt[1000000];
int sz[N * 4], mx;
void merge(vector<pii> &a, const vector<pii> &b, const vector<pii> &c) {
no++;
for(pii p : b) dt[p.second] += p.first;
for(pii p : c) dt[p.second] += p.first;
a.clear();
for(pii p : b) {
int v = p.second;
if (dt[v]) {
a.push_back(mp(-dt[v], v));
dt[v] = 0;
}
}
for(pii p : c) {
int v = p.second;
if (dt[v]) {
a.push_back(mp(-dt[v], v));
dt[v] = 0;
}
}
sort(a.begin(), a.end());
for(int i = a.size() - 1; ~i; i--) a[i].first = -a[i].first;
while(a.size()>mx+1)a.pop_back();
if(a.size() == mx + 1) {
for(int i = 0; i < a.size() - 1; i++) {
a[i].first -= a.back().first;
}
a.pop_back();
}
}
void build(int x, int l, int r) {
sz[x] = r - l + 1;
if (l == r) {
t[x].push_back(mp(1, a[l]));
return;
}
build(x << 1, l, l + r >> 1);
build(x << 1 | 1, (l + r >> 1) + 1, r);
merge(t[x], t[x << 1], t[x << 1 | 1]);
}
void read(int &x) {
char c; while((c=getchar()) > '9' || c < '0');
x = c - '0'; while((c=getchar()) >= '0' && c <= '9') x = x * 10 + c - '0';
}
pii tag[N * 4];
void putaddtag(int x, int v) {
tag[x].second += v;
for(pii &p : t[x]) p.second += v;
}
void setvalue(int x, int v) {
tag[x] = mp(v, 0);
t[x].clear(); t[x].push_back(mp(sz[x], v));
}
void down(int x) {
if (tag[x].first != 0) {
setvalue(x << 1, tag[x].first);
setvalue(x << 1 | 1, tag[x].first);
tag[x].first = 0;
}
if (tag[x].second != 0) {
putaddtag(x << 1, tag[x].second);
putaddtag(x << 1 | 1, tag[x].second);
tag[x].second = 0;
}
}
void modify(int x, int l, int r, int tl, int tr, int id) {
if (l > tr || r < tl) return;
if (tl <= l && r <= tr) {
if (id == 0) {
putaddtag(x, 1);
} else {
setvalue(x, id);
}
return;
}
down(x);
modify(x << 1, l, l + r >> 1, tl, tr, id);
modify(x << 1 | 1, (l + r >> 1) + 1, r, tl, tr, id);
merge(t[x], t[x << 1], t[x << 1 | 1]);
}
vector<pii> tmp;
void query(int x, int l, int r, int tl, int tr, vector<pii> &w) {
if (l > tr || r < tl) return;
if (tl <= l && r <= tr) {
tmp = w;
merge(w, tmp, t[x]);
return;
}
down(x);
query(x << 1, l, l + r >> 1, tl, tr, w);
query(x << 1 | 1, (l + r >> 1) + 1, r, tl, tr, w);
}
void write(vector<pii> a) {
for(pii b : a) {
cout << b.first << " " << b.second << endl;
}
cout << endl;
}
int main() {
freopen("war.in","r",stdin);
// freopen("war.out","w",stdout);
cin >> n >> m >> p;
mx = 100 / p;
for(int i = 1; i <= n; i++) read(a[i]);
build(1, 1, n);
for(int i = 1; i <= m; i++) {
int ty, l, r; read(ty),read(l),read(r);
if (ty == 1) {
int id; read(id);
modify(1, 1, n, l, r, id);
} else if (ty == 2) {
modify(1, 1, n, l, r, 0);
} else if (ty == 3) {
static vector<pii> g;
g.clear();
query(1, 1, n, l, r, g);
printf("%d ", g.size());
for(pii a : g) {
printf("%d ", a.second);
}
printf("\n");
}
}
}