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;
}
相关文章推荐
- Splay树 + 离散化 —— HDU 3436 Queue-jumpers
- HDU-3436 Queue-jumpers(Splay树)
- hdu 3436 Queue-jumpers(splay)
- HDU 3436--Queue-jumpers (树状数组 or Splay Tree)
- hdu 3436 Queue-jumpers(Splay)
- 【HDU 3436】Queue-jumpers(Splay)
- HDU 3436 Queue-jumpers(SplayTree+离散化)
- HDU 3436 Queue-jumpers
- HDU 3436 Queue-jumpers
- HDU 3436 Queue-jumpers
- HDU 3436 Queue-jumpers (splay tree)
- hdu 3436 Queue-jumpers
- hdu 3436 Queue-jumpers (经典离散化,树状数组实现lower_bound)
- HDU 3436 Queue-jumpers
- HDU 3436 Queue-jumpers
- HDU 3436 Queue-jumpers
- hdu 3436 Queue-jumpers(Splay Tree)
- HDU 3436 Queue-jumpers (Splay tree)
- hdu-3436 Queue-jumpers(伸展树)
- HDU 3436 Queue-jumpers