题解 [CF643G] Choosing Ads
还是先来口胡一个做法:
发现只有每次区间内出现次数 \(\geqslant p\%\) 的数是有用的,考虑怎么合并两个区间
发现新区间内出现次数 \(\geqslant p\%\) 的数一定在原区间出现次数 \(\geqslant p\%\) 的数中间
那么对每个可能的数 \(O(\log n)\) 查询一下在新区间中的出现次数即可
复杂度 \(O(nk\log^2n)\)
然后正解:
- 关于摩尔投票法由绝对众数向出现次数 \(\geqslant p\%\) 的推广:
考虑摩尔投票法是每次从序列里选两个不一样的删掉
令 \(k=\lfloor\frac{100}{p}\rfloor\),那么考虑每次选 \(k+1\) 个两两不同的删掉即可
于是线段树上大力维护这个东西
复杂度 \(O(nk^2\log n)\)
点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 200010
#define fir first
#define sec second
#define ll long long
//#define int long long
char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
int ans=0, f=1; char c=getchar();
while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
return ans*f;
}
int n, m, p;
int a[N], k;
struct vec{
int siz;
pair<int, int> a[11];
vec():siz(0){memset(a, 0, sizeof(a));}
inline pair<int, int>& operator [] (int t) {return a[t];}
inline void set(int val, int cnt) {a[siz=1]={val, cnt};}
}dat[N<<2], ans;
inline vec operator + (vec a, vec b) {
vec ans=a;
for (int i=1; i<=b.siz; ++i) {
for (int j=1; j<=ans.siz; ++j) if (ans[j].fir==b[i].fir) {ans[j].sec+=b[i].sec; goto jump;}
ans[++ans.siz]=b[i];
jump: ;
}
sort(ans.a+1, ans.a+ans.siz+1, [](pair<int, int> a, pair<int, int> b){return a.sec>b.sec;});
for (; ans.siz>k; --ans.siz) for (int i=ans.siz-k; i<ans.siz; ++i) ans[i].sec-=ans[ans.siz].sec;
return ans;
}
#define tl(p) tl[p]
#define tr(p) tr[p]
#define pushup(p) dat[p]=dat[p<<1]+dat[p<<1|1]
int tl[N<<2], tr[N<<2], len[N<<2], tag[N<<2];
void spread(int p) {
if (!tag[p]) return ;
dat[p<<1].set(tag[p], len[p<<1]); tag[p<<1]=tag[p];
dat[p<<1|1].set(tag[p], len[p<<1|1]); tag[p<<1|1]=tag[p];
tag[p]=0;
}
void build(int p, int l, int r) {
tl(p)=l; tr(p)=r; len[p]=r-l+1;
if (l==r) {dat[p].set(a[l], 1); return ;}
int mid=(l+r)>>1;
build(p<<1, l, mid);
build(p<<1|1, mid+1, r);
pushup(p);
}
void upd(int p, int l, int r, int val) {
if (l<=tl(p)&&r>=tr(p)) {dat[p].set(val, len[p]); tag[p]=val; return ;}
spread(p);
int mid=(tl(p)+tr(p))>>1;
if (l<=mid) upd(p<<1, l, r, val);
if (r>mid) upd(p<<1|1, l, r, val);
pushup(p);
}
vec query(int p, int l, int r) {
if (l<=tl(p)&&r>=tr(p)) return dat[p];
spread(p);
int mid=(tl(p)+tr(p))>>1;
if (l<=mid&&r>mid) return query(p<<1, l, r)+query(p<<1|1, l, r);
else if (l<=mid) return query(p<<1, l, r);
else return query(p<<1|1, l, r);
}
signed main()
{
n=read(); m=read(); p=read(); k=100/p;
for (int i=1; i<=n; ++i) a[i]=read();
build(1, 1, n);
for (int i=1,l,r,val; i<=m; ++i) {
if (read()&1) {
l=read(); r=read(); val=read();
upd(1, l, r, val);
}
else {
l=read(); r=read();
ans=query(1, l, r);
printf("%d ", ans.siz);
for (int j=1; j<=ans.siz; ++j) printf("%d ", ans[j].fir);
printf("\n");
}
}
return 0;
}