1:在人物集合 S 中加入一个新的程序员,其代号为 X,保证 X 在当前集合中不存在。
2:在当前的人物集合中询问程序员的mod Y 最小的值。 (为什么统计这个?因为拯救
过世界的人太多了,只能取模)
标签:
按权值分块,<=sqrt(300000)的答案直接爆算,>sqrt(300000)的答案可以枚举x/Y的整数部分。
那么问题就是如何快速计算>x的最小的数并带插入。
注意快速计算>x的最小的数并带删除可以用并查集来做,那么时光倒流一下就行了。
#include<cstdio> #include<cctype> #include<queue> #include<cmath> #include<cstring> #include<algorithm> #define rep(i,s,t) for(int i=s;i<=t;i++) #define dwn(i,s,t) for(int i=s;i>=t;i--) #define ren for(int i=first[x];i!=-1;i=next[i]) using namespace std; inline int read() { int x=0,f=1;char c=getchar(); for(;!isdigit(c);c=getchar()) if(c==‘-‘) f=-1; for(;isdigit(c);c=getchar()) x=x*10+c-‘0‘; return x*f; } const int maxn=300010; const int maxm=100010; int pa[maxn],vis[maxn]; int A[maxm],type[maxm],res[410],ans[maxm]; inline int findset(int x) {return !pa[x]||x==pa[x]?x:pa[x]=findset(pa[x]);} int main() { int SIZE=400; rep(i,1,SIZE) res[i]=1e9; int n=read(); rep(i,1,n) { char s[2];int x; scanf("%s%d",s,&x); if(s[0]==‘A‘) { type[i]=1;vis[x]=1;A[i]=x; rep(i,1,SIZE) res[i]=min(res[i],x%i); } else { if(x<=SIZE) ans[i]=res[x]; else type[i]=2,A[i]=x; } } rep(i,1,300000) if(!vis[i]) pa[i]=i+1; dwn(i,n,1) if(type[i]) { if(type[i]==1) pa[A[i]]=A[i]+1; else { ans[i]=1e9; for(int j=0;j<=300000;j+=A[i]) { int x=findset(max(1,j)); if(x<=300000) ans[i]=min(ans[i],x%A[i]); } } } rep(i,1,n) if(type[i]!=1) printf("%d\n",ans[i]); return 0; }
BZOJ4320: ShangHai2006 Homework
标签:
原文地址:http://www.cnblogs.com/wzj-is-a-juruo/p/4986712.html