LA3699 - Harmony Forever
https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=1700
维护一个数集,支持两个操作:
B x:插入一个数x
A x:查询在mod x意义下最小的数的插入时间,如果有多个输出最近的。
x的范围是[1,500000]。操作数≤40000。
因为x的范围比较小,我们可以分块。另lim=2500。
对于x<lim,我们暴力维护一个数组exist[i][j],代表在mod i意义下等于j的最近位置,插入一次用O(lim)的时间更新,查询O(1)。
对于x≥lim,我们枚举答案对于除以x的商i,易知商≤500000/lim,然后求lower_bound(x×i),更新答案。用splay实现,插入O(log(n)),查询O(log(n)×500000/lim)。
#include<bits/stdc++.h> using namespace std; const int maxn=40015,maxv=500015,lim=2500; struct Tsplay{ struct Tnode{ int n,val;Tnode *f,*c[2]; void link(Tnode *newf,int newn){ n=newn;f=newf; if (n!=2) f->c[n]=this; } }*null,*root,T[maxn]; int tot; void clear(){ tot=0;root=null=T;null->val=-1; null->c[0]=null->c[1]=null; } Tnode *newnode(int v){ Tnode *cur=T+(++tot); cur->n=2;cur->val=v; cur->c[0]=cur->c[1]=cur->f=null; return cur; } void rotate(Tnode *x){ Tnode *y=x->f,*z=y->f;int nx=x->n,ny=y->n; x->link(z,ny);x->c[!nx]->link(y,nx);y->link(x,!nx); } void splay(Tnode *x){ while (x->n!=2){ x->n==x->f->n?rotate(x->f):rotate(x); if (x->n!=2) rotate(x); } root=x; } void insert(int v){ if (root==null){root=newnode(v);return;} Tnode *x=root; while (1){ if (v<x->val){ if (x->c[0]==null){x->c[0]=newnode(v);x->c[0]->link(x,0);splay(x->c[0]);return;} else x=x->c[0]; } else{ if (x->c[1]==null){x->c[1]=newnode(v);x->c[1]->link(x,1);splay(x->c[1]);return;} else x=x->c[1]; } } } int lower_bound(int v){ if (root==null) return -1; Tnode *x=root,*res=null; while (x!=null){ if (x->val>=v){res=x;x=x->c[0];} else x=x->c[1]; } if (res!=null) splay(res); return res->val; } }splay; int n,vis[maxv],exist[lim][lim]; void insert(int x,int t){ if (!vis[x]) splay.insert(x);vis[x]=t; for (int i=1;i<lim;++i) exist[i][x%i]=t; } void query(int x){ if (x<lim){ for (int i=0;i<x;++i) if (exist[x][i]){printf("%d\n",exist[x][i]);return;} printf("-1\n"); } else{ int v=splay.lower_bound(0),d=v; if (v==-1){printf("-1\n");return;} for (int y,i=x;(y=splay.lower_bound(i))!=-1;i+=x) if (y-i<d||(y-i==d&&vis[y]>vis[v])){v=y;d=y-i;} printf("%d\n",vis[v]); } } void solve(){ splay.clear();int tim=0; memset(vis,0,sizeof(vis)); memset(exist,0,sizeof(exist)); for (int i=1;i<=n;++i){ char op[5];int x; scanf("%s%d",op,&x); switch (op[0]){ case 'B':insert(x,++tim);break; case 'A':query(x);break; } } } int main(){ int cases=0; while (scanf("%d",&n)!=EOF&&n){ if (++cases!=1) printf("\n"); printf("Case %d:\n",cases); solve(); } return 0; }