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;
}
posted @ 2021-02-03 20:34  ans20xx  阅读(131)  评论(0编辑  收藏  举报