1:在人物集合 S 中加入一个新的程序员,其代号为 X,保证 X 在当前集合中不存在。 2:在当前的人物集合中询问程序员的mod Y 最小的值。 (为什么统计这个?因为拯救过世界的人太多了,只能取模) N≤100000, 1≤X,Y≤300000
对于询问的\(Y\)进行分块,如果\(Y \le \sqrt{300000}\),开一个数组进行暴力维护 如果\(Y \ge \sqrt{300000}\),枚举每一个\(k \times Y\),找到\(\ge k \times Y\)的最小值,取余就是答案。 找最小值的话,似乎可以用set? 也可以用并查集,每一个数字的father就是在数字集合中出现的第一个大于等于他的数字,正着做的话要不停的插入,比较麻烦,倒着做只有删除操作,比较简单。而且比set的方法少一个\(log\)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
| #include<bits/stdc++.h> using namespace std; int n; char c[100010]={}; int x[100010]={}; int ans[100010]={}; bool nu[300010]={}; int fa[300010]={}; int q[610]={}; int ff(int x) { if(x==fa[x]) return x; fa[x]=ff(fa[x]); return fa[x]; } int main() { scanf("%d",&n); for(int i=1;i<=600;i++) { q[i]=2147483600; } for(int i=1;i<=n;i++) { c[i]=getchar(); while(c[i]!='A'&&c[i]!='B') { c[i]=getchar(); } scanf("%d",&x[i]); if(c[i]=='A') { nu[x[i]]=1; for(int j=1;j<=600;j++) { q[j]=min(q[j],x[i]%j); } } else { if(x[i]<=600) ans[i]=q[x[i]]; } } fa[300001]=300001; for(int i=300000;i>=0;i--) { if(nu[i]==1) fa[i]=i; else { fa[i]=i+1; ff(i); } } for(int i=n;i>=1;i--) { if(c[i]=='A') { fa[x[i]]=x[i]+1; ff(x[i]); } else if(x[i]>600) { int o=2147483600; int k=0; while(1) { if(k*x[i]>300000) break; int t=ff(k*x[i]); if(t==300001) break; o=min(o,t%x[i]); k++; } ans[i]=o; } } for(int i=1;i<=n;i++) { if(c[i]=='B') { printf("%d\n",ans[i]); } } return 0; }
|