CF 1476G Minimum Difference 题解
首先它显然需要用带修莫队,问题就是如何求最小极差。
这种出现次数相关的题有一个非常巧妙的性质:
在做莫队时维护
要注意莫队加入一个数的时候新的值插入链表的哪个位置要分类讨论一下。
#include<bits/stdc++.h>
#define ll long long
#define ff(i,s,e) for(int i=(s);i<=(e);++i)
using namespace std;
inline int read(){
int x=0,f=1;
char ch=getchar();
while(ch>'9'||ch<'0'){if(ch=='-') f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
const int N=1e5+5,lim=1e5;
int n,m,a[N],siz,bel[N],cc,cq,ans[N];
struct qwq{
int l,r,k,t,id;
bool operator < (const qwq &a) const{
if(bel[l]!=bel[a.l]) return bel[l]<bel[a.l];
if(bel[r]!=bel[a.r]) return bel[r]<bel[a.r];
return t<a.t;
}
}q[N];
struct qaq{
int pos,x;
}c[N];
int tong[N],cnt[N],pre[N],nxt[N];
inline void erase(int x){
nxt[pre[x]]=nxt[x],pre[nxt[x]]=pre[x];
}
inline void ins(int pos,int x){
nxt[x]=nxt[pos],pre[x]=pos,nxt[pos]=x,pre[nxt[x]]=x;
}
inline void add(int x){
int &tmp=cnt[x];
--tong[tmp];
if(!tong[tmp]) erase(tmp);
++tmp,++tong[tmp];
if(tong[tmp]==1) ins(tong[tmp-1]?tmp-1:pre[tmp-1],tmp);
}
inline void del(int x){
int &tmp=cnt[x];
--tong[tmp];
if(!tong[tmp]) erase(tmp);
--tmp,++tong[tmp];
if(tong[tmp]==1) ins(pre[tmp+1],tmp);
}
inline void change(int x,int i){
if(c[x].pos>=q[i].l&&c[x].pos<=q[i].r){
del(a[c[x].pos]),add(c[x].x);
}
swap(a[c[x].pos],c[x].x);
}
signed main(){
n=read(),m=read(),siz=pow(n,0.66),tong[0]=n+1,nxt[0]=lim+1;
ff(i,1,n) a[i]=read(),bel[i]=(i+siz-1)/siz;
ff(i,1,m){
int op=read(),x=read(),y=read();
if(op==1) q[++cq]={x,y,read(),cc,cq};
else c[++cc]={x,y};
}
sort(q+1,q+cq+1);
int l=1,r=0,tim=0;
ff(i,1,cq){
while(l>q[i].l) add(a[--l]);
while(r<q[i].r) add(a[++r]);
while(l<q[i].l) del(a[l++]);
while(r>q[i].r) del(a[r--]);
while(tim<q[i].t) change(++tim,i);
while(tim>q[i].t) change(tim--,i);
int mn=1e9;
for(int l=nxt[0],r=0,sum=0;r<=lim;){
while(r<=lim&&sum<q[i].k) r=nxt[r],sum+=tong[r];
while(sum>=q[i].k) mn=min(mn,r-l),sum-=tong[l],l=nxt[l];
}
ans[q[i].id]=mn==1e9?-1:mn;
}
ff(i,1,cq) printf("%d\n",ans[i]);
return 0;
}