1. 程式人生 > >[BZOJ4320][ShangHai2006]Homework(根號分治+並查集)

[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 }