发现自己的博客里没有写过平衡树的文章,正好最近复习平衡树就来更新一下吧。
题目大意:
1、插入一位玩家或者更新一位玩家的成绩
2、询问某位玩家的排名
3、询问某一排名后的10位玩家的名字
若两名玩家成绩相同,则先输入的排名高。
玩家通过姓名给出,姓名不超过10个字符。
这题有bug,题目上说成绩不超过8位,实际出现了10位数。
按照成绩建平衡树。
对所有名字建一棵trie树,名字对应的节点记录对应的splay上的节点。
1、插入或更新先在trie树上找到对应节点,如果是更新就删除原来的节点,之后插入平衡树即可。
注意:先插入的排名高
2、找到对应的节点旋转到根,左子树大小即为排名。
3、提取区间[l,r],把l-1旋转到根,把r+1旋转到根的右儿子,中序遍历r+1的左儿子即可。
#include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<algorithm> #include<iostream> #define inf 1000000000000000000ll #define maxn 300010 using namespace std; int ch[maxn][2],fa[maxn],size[maxn],num[maxn]; int Ch[maxn][26],f[maxn]; long long w[maxn]; int tag[maxn],st[20]; char s[101],s1[1010],c[maxn]; int tot,cnt,n,m,T,root,len,Cnt; void print(int x) { int len1=0; while (x) st[++len1]=x,x=f[x]; while (len1) s1[++len]=c[st[len1--]]; s1[++len]=' '; } int dir(int x) { return x==ch[fa[x]][1]; } void update(int x) { size[x]=size[ch[x][0]]+size[ch[x][1]]+1; } void rotate(int x) { int y=fa[x],z=fa[y],b=dir(x),a=ch[x][!b]; if (z==0) root=x; else { int c=dir(y);ch[z][c]=x; } fa[x]=z;fa[y]=x;ch[x][!b]=y;ch[y][b]=a; if (a) fa[a]=y; update(y);update(x); } void splay(int x,int i) { while (fa[x]!=i) { int y=fa[x],z=fa[y]; if (z==i) rotate(x); else { int b=dir(x),c=dir(y); if (b^c) { rotate(x);rotate(x); } else { rotate(y);rotate(x); } } } } int find_k(int x,int k) { if (size[ch[x][0]]==k-1) return x; if (size[ch[x][0]]>k-1) return find_k(ch[x][0],k); else return find_k(ch[x][1],k-size[ch[x][0]]-1); } int find_pre(int x,long long d)//成绩小于d的最大的节点 { if (!x) return x; if (w[x]>=d) return find_pre(ch[x][0],d); else { int y=find_pre(ch[x][1],d); if (y) return y; else return x; } } void insert(long long d) { int x=find_pre(root,d);splay(x,0); int y=find_k(ch[x][1],1);splay(y,x); tot++;w[tot]=d;size[tot]=1;fa[tot]=y;ch[y][0]=tot; update(y);update(x); } void del(int d) { splay(d,0); int x=find_k(ch[d][0],size[ch[d][0]]);splay(x,0); int y=find_k(ch[x][1],2);splay(y,x); fa[ch[y][0]]=0;ch[y][0]=0; update(y);update(x); } int query(int x) { splay(x,0); return size[ch[x][1]]; } void dfs(int x) { if (ch[x][1]) dfs(ch[x][1]); print(num[x]); if (ch[x][0]) dfs(ch[x][0]); } void solve(int d) { int x=find_k(root,size[root]-d+1);splay(x,0); int y=find_k(ch[x][0],max(size[ch[x][0]]-10,1));splay(y,x); dfs(ch[y][1]); for (int i=1;i<len;i++) printf("%c",s1[i]);printf("\n"); } void Change(long long d) { int n=strlen(s+1),x=0; for (int i=1;i<=n;i++) { if (!Ch[x][s[i]-'A']) {Ch[x][s[i]-'A']=++cnt;c[cnt]=s[i];f[cnt]=x;} x=Ch[x][s[i]-'A']; } if (tag[x]) del(tag[x]); else Cnt++; insert(d); tag[x]=tot;num[tot]=x; } void Query() { int n=strlen(s+1),x=0; for (int i=1;i<=n;i++) x=Ch[x][s[i]-'A']; printf("%d\n",query(tag[x])); } int calc() { int x=0; for (int i=1;i<strlen(s);i++) x=x*10+s[i]-'0'; return x; } int main() { tot=2;root=1; fa[1]=0;size[1]=2;num[1]=0;w[1]=-inf;ch[1][1]=2; fa[2]=1;size[2]=1;num[2]=0;w[2]=inf; scanf("%d",&T); while (T--) { long long x; scanf("%s",s); if (s[0]=='+') { scanf("%lld",&x); Change(x); } if (s[0]=='?' && s[1]>='A' && s[1]<='Z') Query(); else if (s[0]=='?') {len=0;solve(calc());} } return 0; }