【題解】CF1476G Minimum Difference
阿新 • • 發佈:2021-10-04
莫隊模板題。
首先這個問題不弱於帶修數顏色,所以考慮帶修莫隊。
同時 \(cnt\) 的取值不超過 \(\sqrt{n}\) 種,所以我們可以用連結串列維護出現的 \(cnt\) 取值。
對於每次詢問,將這 \(\sqrt{n}\) 種 \(cnt\) 從小到大排序,答案就是最短的連續一段滿足出現次數之和 \(\ge k\) 。
我們從小到大列舉右端點,左端點單調,直接雙指標即可。
時間複雜度 \(\mathcal{O}(n^{\frac{5}{3}}+m\sqrt{n}\log\sqrt{n})\),基數排序可以做到 \(\mathcal{O}(n^\frac{5}{3}+m\sqrt{n})\)
前者手算一下大概 \(6\times 10^8\) 運算,實測 \(2s\) 毫無壓力。
#include<bits/stdc++.h> #define rep(i,a,b) for(register int i=a;i<=b;i++) #define pre(i,a,b) for(register int i=a;i>=b;i--) #define N 100005 using namespace std; int n,m,a[N],bas,t,T,p[N],u[N],c[N],f[N],nxt[N],pre[N],ans[N],sta[N]; struct node{ int op,x,l,r,id; bool operator<(const node o)const{ if(l/bas!=o.l/bas)return l<o.l; if(r/bas!=o.r/bas)return r<o.r; return id<o.id; } }q[N]; inline void rem(int x){ if(!x)return; pre[nxt[x]]=pre[x]; nxt[pre[x]]=nxt[x]; } inline void add(int x){ if(!x)return; pre[nxt[0]]=x; nxt[x]=nxt[0]; pre[x]=0;nxt[0]=x; } inline void ins(int x){ c[f[x]]--; if(!c[f[x]])rem(f[x]); f[x]++; if(!c[f[x]])add(f[x]); c[f[x]]++; } inline void del(int x){ c[f[x]]--; if(!c[f[x]])rem(f[x]); f[x]--; if(!c[f[x]])add(f[x]); c[f[x]]++; } inline int calc(int k){ register int top=0,sum=0,cur=nxt[0],ed=0x3f3f3f3f; while(cur)sta[++top]=cur,cur=nxt[cur]; sort(sta+1,sta+top+1);int j=1; rep(i,1,top){ sum+=c[sta[i]]; while(sum-c[sta[j]]>=k)sum-=c[sta[j++]]; if(sum>=k)ed=min(ed,sta[i]-sta[j]); } if(ed==0x3f3f3f3f)return ~0; return ed; } char buf[1<<22],*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 x=0;char ch=getchar(); while(!isdigit(ch))ch=getchar(); while(isdigit(ch))x=(x<<1)+(x<<3)+(ch^48),ch=getchar(); return x; } int main(){ bas=pow(n=read(),0.666666);m=read(); rep(i,1,n)a[i]=read(); rep(i,1,m){ if(read()==1){ ++t;q[t].op=t,q[t].l=read(),q[t].r=read(),q[t].x=read(),q[t].id=T; } else{ ++T;p[T]=read(),u[T]=read(); } } sort(q+1,q+t+1); register int l=1,r=1,tm=0;ins(a[1]); rep(i,1,t){ while(l>q[i].l)ins(a[--l]); while(r<q[i].r)ins(a[++r]); while(l<q[i].l)del(a[l++]); while(r>q[i].r)del(a[r--]); while(tm<q[i].id){ ++tm; if(p[tm]>=l&&p[tm]<=r)del(a[p[tm]]),ins(u[tm]); swap(a[p[tm]],u[tm]); } while(tm>q[i].id){ if(p[tm]>=l&&p[tm]<=r)del(a[p[tm]]),ins(u[tm]); swap(a[p[tm]],u[tm]),tm--; } ans[q[i].op]=calc(q[i].x); } rep(i,1,t)printf("%d\n",ans[i]); return 0; }