USACO 2025 Open, Gold - B
博客园食用更佳。
比较唐的根号做法。
记
考虑对
-
对于
lim\leq B 的情况:记
\displaystyle mx_i=\max_{tot_j\geq i} j ,\displaystyle mn_i=\min_{tot_j\geq i} j 。考虑枚举最后可能的tot_i ,则答案为\displaystyle \max_{i\geq 1} mx_i-mn_{lim-i} 。 -
对于
lim \gt B 的情况:称
tot_x \geq \lceil \frac B2 \rceil 的x 为大数,则由\displaystyle \sum_i tot_i =n 可知大数的个数不会超过\lfloor\frac{2n}B\rfloor 个,同时一组合法的(i,j) 中至少有一个大数。考虑枚举大数,则答案为:\displaystyle \max_{tot_i \geq \lceil \frac B2 \rceil} \max\{i-mn_{lim-tot_i},mx_{lim-tot_i}-i\} 。
现在的问题是如何
使用 set 做到
时间复杂度
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+9;
const int B=4e2;
int a[N],cnt[N],mx[N],mn[N],n,q;
set<int> s[N],all,big;
inline void Update(int x){
mx[x]=mx[x+1],mn[x]=mn[x+1];
if(s[x].size()){
mx[x]=max(mx[x],*s[x].rbegin());
mn[x]=min(mn[x],*s[x].begin());
}
}
inline void Veto(int x){
all.erase(cnt[x]);
s[cnt[x]].erase(x);
Update(cnt[x]);
if(cnt[x]>=(B>>1)) big.erase(x);
cnt[x]--;
if(cnt[x]>=(B>>1)) big.insert(x);
all.insert(cnt[x]);
s[cnt[x]].insert(x);
}
inline void Vote(int x){
all.erase(cnt[x]);
s[cnt[x]].erase(x);
if(cnt[x]>=(B>>1)) big.erase(x);
cnt[x]++;
if(cnt[x]>=(B>>1)) big.insert(x);
all.insert(cnt[x]);
s[cnt[x]].insert(x);
Update(cnt[x]);
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
#define endl '\n'
cin>>n>>q;
for(int i=1;i<=n;i++) cin>>a[i];
mx[n+1]=0,mn[n+1]=n+1;
for(int i=1;i<=n;i++) cnt[a[i]]++;
for(int i=1;i<=n;i++) s[cnt[i]].insert(i);
for(int i=n;i>=0;i--) Update(i);
for(int i=1;i<=n;i++) all.insert(cnt[i]);
for(int i=1;i<=n;i++) if(cnt[i]>=(B>>1)) big.insert(i);
while(q--){
int i,x;
cin>>i>>x;
Veto(a[i]);
a[i]=x;
Vote(a[i]);
int lim=*all.rbegin();
if(lim<=B){
int ans=0;
for(int i=1;i<=lim;i++){
ans=max(ans,mx[max(lim-i,1)]-mn[i]);
ans=max(ans,mx[i]-mn[max(lim-i,1)]);
}
cout<<ans<<endl;
}else{
int ans=0;
for(int i:big){
ans=max(ans,mx[max(lim-cnt[i],1)]-i);
ans=max(ans,i-mn[max(lim-cnt[i],1)]);
}
cout<<ans<<endl;
}
}
return 0;
}