ShangHai2006 Homework
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 918 Solved: 460
[Submit][Status][Discuss]
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
A 3
A 5
B 6
A 9
B 4
Sample Output
3
1
1
HINT
【样例说明】
在第三行的操作前,集合里有 3、5 两个代号,此时 mod 6 最小的值是 3 mod 6 = 3;
在第五行的操作前,集合里有 3、5、9,此时 mod 4 最小的值是 5 mod 4 = 1;
1.插入一个数X
2.询问所有数 mod Y的最小值
将询问按照Y≤3∗105−−−−−√和Y>3∗105−−−−−√两种分类
Y≤3∗105−−−−−√:开一个数组ansY代表当询问为Y的时候的答案,每插入一个数枚举1≤i≤3∗105−−−−−√用X mod i更新ansi
Y>3∗105−−−−−√:枚举Y的倍数kY,对于每个kY我们需要找到集合中大于等于kY的数中最小的那个
log系列显然会T
考虑并查集,类似于花神游历各国那个题一样,我们可以利用并查集完成【删除一个数,迅速找到一个位置后面第一个没有被删除的数】
但是这个题是插入一个数啊?
倒着做就行了
1 #include<cstring> 2 #include<cmath> 3 #include<algorithm> 4 #include<iostream> 5 #include<cstdio> 6 7 #define T 300007 8 #define B 507 9 #define M 300007 10 #define ll long long 11 using namespace std; 12 inline int read() 13 { 14 int x=0,f=1;char ch=getchar(); 15 while(ch>'9'||ch<'0'){if (ch=='-') f=-1;ch=getchar();} 16 while(ch<='9'&&ch>='0'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();} 17 return x*f; 18 } 19 20 int n; 21 int fa[M],opt[M],num[M]; 22 int mn[M],ans[M]; 23 24 int find(int x) 25 { 26 return fa[x]==x?fa[x]:fa[x]=find(fa[x]); 27 } 28 int main() 29 { 30 scanf("%d",&n); 31 memset(mn,127,sizeof(mn)); 32 for(int i=1;i<=T;i++)fa[i]=i+1; 33 for(int i=1;i<=n;i++) 34 { 35 char s[5]; 36 scanf("%s%d",s,&num[i]); 37 opt[i]=s[0]-'A'; 38 if(opt[i]==0) 39 { 40 for(int j=1;j<=B;j++) 41 mn[j]=min(mn[j],num[i]%j); 42 fa[num[i]]=num[i]; 43 } 44 else if(num[i]<=B) ans[i]=mn[num[i]]; 45 } 46 for(int i=n;i;i--) 47 { 48 if(opt[i]==0) 49 fa[num[i]]=fa[num[i]+1]; 50 else if(num[i]>B) 51 { 52 ans[i]=find(1)%num[i]; 53 for(int j=num[i];j<=T;j+=num[i]) 54 { 55 int x=find(fa[j]); 56 if(x)ans[i]=min(ans[i],x%num[i]); 57 } 58 } 59 } 60 for(int i=1;i<=n;i++) 61 if(opt[i]==1) 62 printf("%d ",ans[i]); 63 }