[HAOI2008] 排名系统
这道题目我并没有AC,得分停留在81。
我用的是 Hash + Splay 。应该是因为我的 Hash 并不能很好的处理名字只有1个字母的情况。
大致说一下思路。
通过 Hash 建立或找到一名玩家的信息,并在 Splay 中实现各个操作,Hash 起到一种衔接作用。
对于本题名次的排名有一个新的约束,分数相同先上传的名次靠前。
这个我们只需要开一个结构体同时记录得分和上传时间并定义一下大小关系就可以了。
挂上未AC代码。
// q.c #include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> using namespace std; const int M=250000+3,N=26; struct Data { int v,t; Data():v(-1),t(-1) {} bool operator == (const Data &A) const { return v==A.v&&t==A.t; } bool operator > (const Data &A) const { if(v!=A.v) return v>A.v; return t<A.t; } }; struct Hash { static const int seed=999997,mod=300007; int hash[mod+7]; char name[mod][12]; Data w[mod+4]; Hash() { memset(hash,-1,sizeof(hash)); } int locate(char *s) { int len=strlen(s); unsigned int x=0; for(int i=0;i<len;i++) x=x*seed+s[i]-'A'; x%=mod; while(hash[x]!=-1&&(strcmp(name[x],s)!=0)) x++,x%=mod; return x; } Data insert(char *s,Data q) { int x=locate(s); if(hash[x]!=-1) { Data y=w[x]; w[x]=q; return y; } hash[x]=1; strcpy(name[x],s); w[x]=q; return q; } }h; struct SplayTree { int root,cnt,l[M],r[M],f[M],s[M]; char name[M][15]; Data w[M]; SplayTree():root(0),cnt(0) { memset(l,0,sizeof(l)); memset(r,0,sizeof(r)); memset(f,0,sizeof(f)); memset(s,0,sizeof(s)); } void update(int x) { s[x]=s[l[x]]+s[r[x]]+1; } void l_rot(int x) { int y=f[x],z=f[y]; f[x]=z; if(z) y==l[z]?l[z]=x:r[z]=x; if(l[x]) f[l[x]]=y; r[y]=l[x],f[y]=x,l[x]=y; update(y),update(x); } void r_rot(int x) { int y=f[x],z=f[y]; f[x]=z; if(z) y==l[z]?l[z]=x:r[z]=x; if(r[x]) f[r[x]]=y; l[y]=r[x],f[y]=x,r[x]=y; update(y),update(x); } int minx(int x) { while(r[x]) x=r[x]; return x; } int find(int o,Data x) { if(w[o]==x) return o; else if(x>w[o]) return find(l[o],x); else return find(r[o],x); } void splay(int x,int &p) { int y=f[x],z=f[y],q=f[p]; while(y!=q) { if(z==q) x==l[y]?r_rot(x):l_rot(x); else if(x==l[y]&&y==l[z]) r_rot(y),r_rot(x); else if(x==l[y]&&y==r[z]) r_rot(x),l_rot(x); else if(x==r[y]&&y==l[z]) l_rot(x),r_rot(x); else l_rot(y),l_rot(x); y=f[x],z=f[y]; } p=x; } void merge(int x,int y) { if(!x) { root=y; return ; } if(!y) { root=x; return ; } int fx=minx(x); splay(fx,x); f[y]=x,r[x]=y,root=x; update(x); } void insert(int &o,int fa,Data x,char *str) { if(!o) { o=++cnt,f[o]=fa,s[o]=1,w[o]=x; strcpy(name[o],str); } else if(x>w[o]) insert(l[o],o,x,str); else insert(r[o],o,x,str); update(o); } void delet(int o,Data x) { int po=find(root,x); splay(po,root); f[l[root]]=f[r[root]]=0; merge(l[root],r[root]); } int rank(int o,Data x) { int ans=1,po=o; while(o) { if(w[o]>x) ans+=s[l[o]]+1,po=o,o=r[o]; else o=l[o]; } splay(po,root); return ans; } int kth(int o,int x) { if(x>s[root]) return -1; int ans=0,po=o; while(o) { if(s[l[o]]+1==x) { ans=o,po=o; break; } else if(x<s[l[o]]+1) o=l[o]; else x-=(s[l[o]]+1),o=r[o]; } splay(po,root); return ans; } void dfs(int o) { if(l[o]) dfs(l[o]); printf("%d %d %s\n",w[o].v,w[o].t,name[o]); if(r[o]) dfs(r[o]); } }tree; int trans(char *s) { int x=0,len=strlen(s); for(int i=0;i<len;i++) x=x*10+s[i]-'0'; return x; } void solve1(char *s,int x,int i) { Data dx; dx.v=x,dx.t=i; Data dy=h.insert(s+1,dx); if(!(dx==dy)) tree.delet(tree.root,dy); tree.insert(tree.root,0,dx,s+1); } void solve2(char *s) { int x=trans(s+1); for(int i=1;i<=10;i++) { int ans=tree.kth(tree.root,x+i-1); if(ans==-1) break; printf("%s ",tree.name[ans]); } printf("\n"); } void solve3(char *s) { Data dx=h.w[h.locate(s+1)]; printf("%d\n",tree.rank(tree.root,dx)); } int main() { freopen("rank.in","r",stdin); freopen("rank.out","w",stdout); int m,x; char s[13]; scanf("%d",&m); for(int i=1;i<=m;i++) { scanf("%s",s); if(s[0]=='+') scanf("%d",&x),solve1(s,x,i); else if(s[1]>='1'&&s[1]<='9') solve2(s); else solve3(s); } return 0; }