BZOJ4320 ShangHai2006 Homework

Description

  1:在人物集合 S 中加入一个新的程序员,其代号为 X,保证 X 在当前集合中不存在。 
  2:在当前的人物集合中询问程序员的mod Y 最小的值。 (为什么统计这个?因为拯救
过世界的人太多了,只能取模) 

Input

第一行为用空格隔开的一个个正整数 N。 
接下来有 N 行,若该行第一个字符为“A” ,则表示操作 1;若为“B”,表示操作 2; 
其中 对于 100%的数据:N≤100000, 1≤X,Y≤300000,保证第二行为操作 1。 

Output

对于操作 2,每行输出一个合法答案。 

Sample Input

5
A 3
A 5
B 6
A 9
B 4

Sample Output

3
1

HINT

【样例说明】 

 

  在第三行的操作前,集合里有 3、5 两个代号,此时 mod 6 最小的值是 3 mod 6 = 3; 

 

  在第五行的操作前,集合里有 3、5、9,此时 mod 4 最小的值是 5 mod 4 = 1;
 
 
正解:分块+并查集
解题报告:
  显然小数据可以直接暴力,对于大数据我们考虑别的方法。
  对于大数据而言我们通过枚举其倍数,如果可以的快速得到大于某个数的最小值那么我们就可以快速得出答案。但是我们考虑要添加数,但是并查集如果维护的是大于某个数的最小值,正着做无法维护,如果是倒着做的话会更有利,因为删除数只需要改变当前数的father即可。所以我们考虑小数据正着暴力,大数据倒着枚举倍数然后查大于当前数的最小值。
  小数据与大数据的分界点在根号处理论上最快,实验表明这道题在300附近是最优的。
 

 

 1 //It is made by jump~
 2 #include <iostream>
 3 #include <cstdlib>
 4 #include <cstring>
 5 #include <cstdio>
 6 #include <cmath>
 7 #include <algorithm>
 8 #include <ctime>
 9 #include <vector>
10 #include <queue>
11 #include <map>
12 #include <set>
13 #ifdef WIN32   
14 #define OT "%I64d"
15 #else
16 #define OT "%lld"
17 #endif
18 using namespace std;
19 typedef long long LL;
20 const int MAXN = 100011;
21 const int MAXM = 300011;
22 const int size = 300;
23 int n,father[MAXM],N;
24 bool vis[MAXM];
25 char ch[2];
26 int ans[size+1];
27 struct wen{
28     int type,x;
29     int ans;    
30 }q[MAXN];
31 
32 inline int getint()
33 {
34        int w=0,q=0;
35        char c=getchar();
36        while((c<'0' || c>'9') && c!='-') c=getchar();
37        if (c=='-')  q=1, c=getchar();
38        while (c>='0' && c<='9') w=w*10+c-'0', c=getchar();
39        return q ? -w : w;
40 }
41 
42 inline int find(int x){
43     if(father[x]!=x) father[x]=find(father[x]);
44     return father[x];
45 }
46 
47 inline void work(){
48     n=getint();
49     for(int i=1;i<=size;i++) ans[i]=(1<<30);
50     for(int i=1;i<=n;i++) {
51     scanf("%s",ch); q[i].x=getint(); 
52     if(ch[0]=='A') { q[i].type=1; vis[q[i].x]=1; N=max(N,q[i].x); for(int j=1;j<=size;j++)  ans[j]=min(ans[j],q[i].x%j);  } 
53     else { q[i].type=2; if(q[i].x<=size) q[i].ans=ans[q[i].x]; }
54     }
55     for(int i=1;i<=N;i++) if(vis[i]) father[i]=i; else father[i]=i+1;//father[i]表示大于i的最小值
56     father[N+1]=N+1;    
57     for(int i=n;i>=1;i--) {
58     if(q[i].type==1) { father[q[i].x]=q[i].x+1; }//改变原来的值
59     else if(q[i].x>size) {
60         q[i].ans=find(1);        
61         for(int j=q[i].x;j<=N;j+=q[i].x) {
62         int lin=find(j);
63         if(lin<=N) q[i].ans=min(lin%q[i].x,q[i].ans);//记得取模
64         else break;
65         }
66     }
67     }
68     for(int i=1;i<=n;i++) if(q[i].type==2) printf("%d\n",q[i].ans);
69 }
70 
71 int main()
72 {
73   work();
74   return 0;
75 }

 

posted @ 2016-08-08 21:29  ljh_2000  阅读(274)  评论(0编辑  收藏  举报