您的位置:首页 > 产品设计 > UI/UE

HDU 3436 Queue-jumpers(Splay)

2016-08-28 19:39 375 查看

Queue-jumpers

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)

Total Submission(s): 3545    Accepted Submission(s): 962


[align=left]Problem Description[/align]
Ponyo and Garfield are waiting outside the box-office for their favorite movie. Because queuing is so boring, that they want to play a game to kill the time. The game is called “Queue-jumpers”. Suppose that there are N people numbered
from 1 to N stand in a line initially. Each time you should simulate one of the following operations:

1.  Top x :Take person x to the front of the queue

2.  Query x: calculate the current position of person x

3.  Rank x: calculate the current person at position x

Where x is in [1, N].

Ponyo is so clever that she plays the game very well while Garfield has no idea. Garfield is now turning to you for help.

 

[align=left]Input[/align]
In the first line there is an integer T, indicates the number of test cases.(T<=50)

In each case, the first line contains two integers N(1<=N<=10^8), Q(1<=Q<=10^5). Then there are Q lines, each line contain an operation as said above.

 

[align=left]Output[/align]
For each test case, output “Case d:“ at first line where d is the case number counted from one, then for each “Query x” operation ,output the current position of person x at a line, for each “Rank x” operation, output the current
person at position x at a line.
 

[align=left]Sample Input[/align]

3
9 5
Top 1
Rank 3
Top 7
Rank 6
Rank 8
6 2
Top 4
Top 5
7 4
Top 5
Top 2
Query 1
Rank 6

 

[align=left]Sample Output[/align]

Case 1:
3
5
8
Case 2:
Case 3:
3
6

【思路参考】爱神

【解题方法】

仔细分析3种操作:

RANK就是找出第K位是多少

TOP是将某个人移至队首,对中间区间没有影响

QUERY是某个人的位置

可以发现将QUERY和TOP操作的点单独出来,还需要把中间的其它区间缩点,只需要保存区间长度即可,便于之后的统计名次。

对于缩点后的区间,内部是有序的,而且操作不改变顺序,在统计的时候,只需要由名次和起点就能找到,对于QUERY操作,也可以把操作点也分离出来,不知道会不会TLE

离散化之后便是Splay的基本操作了。

TOP:将目标点旋转至根部,然后删除,最后插入到队首

RANK:通过size查找即可,注意每个点的size是区间长度

QUERY:把该点旋转至根部,左子树的大小+1便是结果

【AC 代码】
//
//HDU 3436
//Created by just_sort 2016/8/28
//All rights Reserved
//

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 200010;

int n,q,cnt;
int p[maxn],s[maxn],e[maxn],ope[maxn],node[maxn];
char str[maxn][10];
int root,tot,size[maxn],key[maxn],pre[maxn],num[maxn],ch[maxn][2];
inline void pushup(int r)
{
size[r]=size[ch[r][0]]+size[ch[r][1]]+num[r];
}
inline void newnode(int &r,int father,int k)
{
r=++tot;
pre[r]=father;
size[r]=e[k]-s[k]+1;
num[r]=e[k]-s[k]+1;
key[r]=k;
node[k]=r;
ch[r][0]=ch[r][1]=0;
}
inline void BuildTree(int &x,int l,int r,int father)
{
if(l>r) return ;
int mid=(l+r)/2;
newnode(x,father,mid);
BuildTree(ch[x][0],l,mid-1,x);
BuildTree(ch[x][1],mid+1,r,x);
pushup(x);
}
void Rotate(int x,int kind)
{
int y=pre[x];
ch[y][!kind]=ch[x][kind];
pre[ch[x][kind]]=y;
if(pre[y])
ch[pre[y]][ch[pre[y]][1]==y]=x;
pre[x]=pre[y];
ch[x][kind]=y;
pre[y]=x;
pushup(y);
}
void Splay(int r,int goal)
{
while(pre[r]!=goal)
{
if(pre[pre[r]]==goal) Rotate(r,ch[pre[r]][0]==r);
else
{
int y=pre[r];
int kind=ch[pre[y]][0]==y;
if(ch[y][kind]==r)
{
Rotate(r,!kind);
Rotate(r,kind);
}
else
{
Rotate(y,kind);
Rotate(r,kind);
}
}
}
pushup(r);
if(goal==0) root=r;
}

int bin(int x)
{
int l=0,r=cnt-1,mid;
while(l<=r)
{
mid=(l+r)/2;
if(s[mid]<=x&&x<=e[mid]) return mid;
if(e[mid]<x) l=mid+1;
else r=mid-1;
}
//return -1;
}

int getmin(int r)
{
while(ch[r][0])
{
r=ch[r][0];
}
return r;
}

//void Delete()
//{
// int k=getmin(ch[root][1]);//找到右孩子中最小的
// Splay(k,root); //旋转过来,使得右子树没有左孩子
// ch[ch[root][1]][0]=ch[root][0];//将原来的左孩子给右子树作为左孩子
// root=ch[root][1];//让右孩子为根
// pre[ch[root][0]]=root;
// pre[root]=0;
//}
//删除
//void Delete()
//{
// int k=getmin(ch[root][1]);
// Splay(k,root);
// ch[ch[root][1]][0]=ch[root][0];
// root=ch[root][1];
// pre[ch[root][0]]=root;
// pre[root]=0;
// pushup(root);
//}
void Delete()
{
int m=getmin(ch[root][1]);
Splay(m,root);
ch[m][0]=ch[root][0];
pre[ch[root][0]]=m;
root=m;
pre[root]=0;
pushup(root);
}
//插入
void Insert(int &r,int k,int father)
{
if(r==0){
newnode(r,father,k);
return ;
}
Insert(ch[r][0],k,r);//因为是插入到队首,所以一直往左子树找
pushup(r);
}
//Top操作
void Top(int x)
{
int k=bin(x);
int y=node[k]; //找到这个点所在区间的编号
Splay(y,0); //旋转到根部
if(!ch[root][0]||!ch[root][1]){//左右孩子不完整,直接将孩子拉到根部
root=ch[root][0]+ch[root][1];
pre[root]=0;
}
else{
Delete();//删除节点
}
Insert(root,k,0);//再插入
Splay(tot,0);//很关键的一步,不加TLE
}

int get_Rank(int x)
{
int k=bin(x);
int y=node[k];//找到这个点所在区间的编号
Splay(y,0);
return size[ch[root][0]]+1;
}

int get_Kth(int r,int k)
{
int t=size[ch[r][0]];
if(k<=t) return get_Kth(ch[r][0],k);
else if(k<=t+num[r]) return s[key[r]]+(k-t)-1;
else
return get_Kth(ch[r][1],k-t-num[r]);
}

int main()
{
int cas=1,T;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&q);
int to=0;
p[to++]=0;
for(int i=0; i<q; i++)
{
scanf("%s%d",str[i],&ope[i]);
if(str[i][0]=='T'||str[i][0]=='Q')
{
p[to++]=ope[i];
}
}
p[to++]=n;
sort(p,p+to);
cnt=0;
for(int i=1; i<to; i++)
{
if(p[i]!=p[i-1])
{
if(p[i]-p[i-1]>1)
{
s[cnt]=p[i-1]+1;
e[cnt]=p[i]-1;
cnt++;
}
s[cnt]=p[i];
e[cnt]=p[i];
cnt++;
}
}
//cout<<cnt<<endl;
//system("pause");
//
root=tot=0;
pre[0]=size[0]=ch[0][0]=ch[0][1]=0;
num[0]=key[0]=0;
BuildTree(root,0,cnt-1,0);
//
printf("Case %d:\n",cas++);
for(int i=0; i<q; i++)
{
if(str[i][0]=='T')
{
Top(ope[i]);
}
else if(str[i][0]=='Q')
{
printf("%d\n",get_Rank(ope[i]));
}
else{
printf("%d\n",get_Kth(root,ope[i]));
}
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: