【bzoj1862】[Zjoi2006]GameZ游戏排名系统 splay+trie

发现自己的博客里没有写过平衡树的文章,正好最近复习平衡树就来更新一下吧。

题目大意:

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;
}


你可能感兴趣的:(【bzoj1862】[Zjoi2006]GameZ游戏排名系统 splay+trie)