好题集 (7) - LG P9809 [SHOI2006] 作业 Homework
题意:维护一个集合 \(S\),有 \(n\) 此操作,操作分为修改和查询。修改时将给定的 \(x\) 插入 \(S\) 中,查询时对于给定的 \(y\),求 \(\forall x\in S,\min (x\bmod y)\)。\(n\le 10^5\),\(x,y\le 3\times 10^5\)。
看到诡异取模,联想到对 \(y\) 根号分治。设阈值为 \(B\),分 \(y\le B\) 和 \(y>B\) 两种情况讨论。
首先对于 \(\forall i\in[1,B]\),都维护一个 \(val_i\) 表示已有的 \(x\) 中,\(\min (x\bmod i)\)。对于 \(y\le B\) 的查询操作,直接将 \(val_y\) 作为答案即可,这一步是 \(O(1)\) 的;每插入一个新的 \(x\),都对应更新 \(val_i\),这一步是 \(O(B)\) 的。
考虑对于 \(y>B\) 的查询应该怎么做。我们把对每个 \(x\) 取模的式子列出来:
其中 \(r\) 是余数,\(\min r\) 即为答案。
设 \(a\) 为商,再把式子变一下形:
观察发现,\(y>B\) 就意味着 \(a<\frac{x}{B}\)。这是一个很重要的性质,我们可以利用这个性质来枚举 \(a\),并将每个 \(a\) 对应的 \(r\) 取最小值作为答案。枚举的过程是 \(O(\frac{x}{B})\) 的。
考虑我们当前枚举到了一个 \(a\),如何求出对应的 \(r\)。显然这时 \(x\) 取 \(ay\) 的后继(可以取等)是最优的。如果这样的 \(x\) 存在,那么这个 \(a\) 对应的答案就是 \(x\bmod y\)。
于是对于一次 \(y>B\) 的查询,我们一共要求 \(O(\frac{V}{B})\) 次后继;而对于一次修改,我们只需插入一次。显然常规值域分块的 \(O(1)\) 插入,\(O(\sqrt{n})\) 求后继是不够看的;平衡树等二分数据结构也不是优。于是不难想到改变值域分块的维护方式,牺牲一部分插入的复杂度来平衡求后继的复杂度,做到 \(O(\sqrt{n})\) 插入,\(O(1)\) 求后继。
容易想到维护每个数在块内的后继(若无则设为 $\infty $)和每块右端点上的数在后面所有块中的后继。更新时容易以 \(O(\sqrt{n})\) 的复杂度维护,查询时直接将两个值取最小即可,做到 \(O(1)\)。
发现 \(B\) 取 \(\sqrt{V}\) 时比较优,此时总复杂度为 \(O(n\sqrt{V})\)。
代码(题中的 \(y\) 在代码中叫 \(x\)):
#include<iostream>
#include<cmath>
#include<queue>
using namespace std;
const int N=3e6+5;
const int B=550;
int n;
int val[N];
namespace OIfast{
char buf[1<<21],*p1,*p2,*top,buffer[1<<21];
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?0:*p1++)
#define gc getchar()
inline int read(){
int n=0;static char c=gc;
while(!isdigit(c))c=gc;
while(isdigit(c))n=(n<<3)+(n<<1)+(c^48),c=gc;
return n;
}
}using namespace OIfast;
namespace FK{
const int M=1e4+5;
int k,tot;
int L[M],R[M],loc[N];
int nxt[N],nxt_[M];
inline void getmn(int &a,int b){
return a=(a<b?a:b),void();
}
inline void init(){
k=550,tot=ceil((3e5)/(1.0*k));
for(int i=1;i<=tot;++i){
L[i]=(i-1)*k,R[i]=min((int)3e5,L[i]+k-1);
nxt_[i]=1e9;
for(int j=L[i];j<=R[i];++j)loc[j]=i,nxt[j]=1e9;
}
for(int i=1;i<=B;++i)val[i]=1e9;
return ;
}
inline void add(int v){
for(int i=L[loc[v]];i<=v;++i)getmn(nxt[i],v);
for(int i=1;i<=loc[v]-1;++i)getmn(nxt_[i],v);
return ;
}
inline int qry(int v){
return min(nxt_[loc[v]],nxt[v]);
}
}using namespace FK;
inline void work(){
char op=gc;while(!isalpha(op))op=gc;
int x=read();
if(1==2){
puts("wow");
}else if(op=='A'){
for(int i=1;i<=B;++i)getmn(val[i],x%i);
add(x);
}else if(op=='B'){
if(x<=B)printf("%d\n",val[x]);
else{
int res=1e9;
for(int i=0;i*x<=3e5;++i)if(qry(i*x)<1e9)getmn(res,qry(i*x)%x);
printf("%d\n",res);
}
}
return ;
}
signed main(){
// freopen("P9809_1.in","r",stdin),freopen("out.txt","w",stdout);
n=read();init();while(n--)work();
return 0;
}
提交记录。

浙公网安备 33010602011771号