发现自己的博客里没有写过平衡树的文章,正好最近复习平衡树就来更新一下吧。
题目大意:
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;
}