[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
",ans[i]);
37     return 0;
38 }
原文地址:https://www.cnblogs.com/HocRiser/p/9907278.html