[BZOJ4320][ShangHai2006]Homework(根号分治+并查集)
对于<=sqrt(300000)的询问,对每个模数直接记录结果,每次加入新数时暴力更新每个模数的结果。
对于>sqrt(300000)的询问,枚举倍数,每次查询大于等于这个倍数的最小数是多少,这个操作通过将询问逆序使用并查集支持。
1 #include<cstdio> 2 #include<algorithm> 3 #define rep(i,l,r) for (int i=(l); i<=(r); i++) 4 using namespace std; 5 6 const int N=300010,M=300000,B=550; 7 char ch; 8 int n,x,a[N],ans[N],q[N],q2[N],fa[N]; 9 int get(int x){ return (fa[x]==x) ? x : fa[x]=get(fa[x]); } 10 11 int main(){ 12 freopen("bzoj4320.in","r",stdin); 13 freopen("bzoj4320.out","w",stdout); 14 scanf("%d",&n); 15 rep(i,0,M) fa[i]=i+1; fa[M+1]=M+1; 16 rep(i,1,B) a[i]=i+1; 17 rep(i,1,n){ 18 scanf(" %c",&ch); 19 if (ch=='A'){ 20 scanf("%d",&x); fa[x]=x; 21 rep(j,1,B) a[j]=min(a[j],x%j); 22 q[i]=1; q2[i]=x; 23 }else{ 24 scanf("%d",&x); 25 if (x<=B) q[i]=0,q2[i]=0,ans[i]=a[x]; else q[i]=0,q2[i]=x; 26 } 27 } 28 for (int i=n; i; i--){ 29 if (q[i]) fa[q2[i]]=q2[i]+1; 30 else if (q2[i]){ 31 ans[i]=M+1; 32 for (int j=0; j<=M; j+=q2[i]) 33 if (get(j)<=M) ans[i]=min(ans[i],get(j)-j); 34 } 35 } 36 rep(i,1,n) if (!q[i]) printf("%d\n",ans[i]); 37 return 0; 38 }