CF1476G. Minimum Difference
CF1476G. Minimum Difference
描述
有一个长为 n 的序列 a。有 m 个查询,每个查询如下:
1 l r k
,从 \([l,r]\) 区间取 k 个不同的数 \(x_1,...x_k\),使得它们之间的数量 cnt 最大差值最小,(也就说,对于任何一种取法,取 k 个数,对每个数出现的次数排序,使得最多出现次数减去最小出现次数最少)2 p x
,修改 \(a_p\) 为 \(x\)。
思路
考虑 \(n\le 10^5\),又涉及到区间的查询和单点修改,可以确定这题可以使用带修莫队求解。
使用莫队维护区间每个数出现的次数 cnt,以及出现次数相同的数的个数,即 ccnt[cnt] (也就是对cnt计数),最后,用数组存放一对数,分别代表出现的次数,有多少个不同的数出现,到这里就可以用双指针维护了,保证双指针内 pair 的 second 和大于等于 k,然后对出现次数差值求个最小值即可,ccnt[] 内容如 1 1 1
ccnt 统计为 1:1 2:1 3:1
,之后可以用 lower_bound 查询得到 vector 数组(ccnt 用 map 统计会在第 9 个点超时)。
代码
#include <bits/stdc++.h>
using namespace std;
const int N=100010,S=1000010;
int n,m,mq,mc,len;
int w[N],cnt[S],ans[N],ccnt[S];
#define x first
#define y second
struct Query{
int id,l,r,t,k;
}q[N];
struct Modify{
int p,c;
}c[N];
int get(int x){
return x/len;
}
bool cmp(const Query &a,const Query &b){
int al=get(a.l),ar=get(a.r);
int bl=get(b.l),br=get(b.r);
if(al!=bl) return al<bl;
if(ar!=br) return ar<br;
return a.t<b.t;
}
void add(int x){
cnt[x]++;
ccnt[cnt[x]]++;
}
void del(int x){
ccnt[cnt[x]]--;
cnt[x]--;
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",w+i);
for(int i=0;i<m;i++){
int op;
int a,b;
scanf("%d%d%d",&op,&a,&b);
if(op==1) {
int k; scanf("%d",&k);
mq++,q[mq]={mq,a,b,mc,k};
}
else c[++mc]={a,b};
}
len=cbrt((double)n*mc+1);
sort(q+1,q+mq+1,cmp);
for(int i=0,j=1,t=0,k=1,res=0;k<=mq;k++){
int id=q[k].id,l=q[k].l,r=q[k].r,tm=q[k].t,qk=q[k].k;
while(i<r) add(w[++i]);
while(i>r) del(w[i--]);
while(j<l) del(w[j++]);
while(j>l) add(w[--j]);
while(t<tm){
t++;
if(c[t].p>=j&&c[t].p<=i){
del(w[c[t].p]);
add(c[t].c);
}
swap(w[c[t].p],c[t].c);
}
while(t>tm){
if(c[t].p>=j&&c[t].p<=i){
del(w[c[t].p]);
add(c[t].c);
}
swap(w[c[t].p],c[t].c);
t--;
}
vector<pair<int,int>> v;
int xx=0;
int tt=1;
v.push_back({-1,-1}); // 占位置
while(ccnt[tt]){
int id=upper_bound(ccnt+tt+1,ccnt+n+1,ccnt[tt],greater<int>())-ccnt;
v.push_back(make_pair(id,ccnt[tt]-ccnt[id]));
tt=id;
}
int s=0;
res=1e5+10;
for(int i=1,j=0;i<v.size();i++){
while(j<v.size()-1&&s<qk){
s+=v[++j].y;
}
if(s>=qk){
res=min(res,v[j].x-v[i].x);
}
s-=v[i].y;
}
if(res>1e5) res=-1;
ans[id]=res;
}
for(int i=1;i<=mq;i++) printf("%d\n",ans[i]);
return 0;
}