443人阅读 评论(0)

# Queue-jumpers

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 3545    Accepted Submission(s): 962

Problem Description
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.

Input
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.

Output
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.

Sample Input
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

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

【思路参考】爱神

【解题方法】

RANK就是找出第K位是多少

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

QUERY是某个人的位置

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

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

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

【AC 代码】

//
//HDU 3436
//Created by just_sort 2016/8/28
//

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


0
0

个人资料
• 访问：411489次
• 积分：16482
• 等级：
• 排名：第746名
• 原创：1274篇
• 转载：21篇
• 译文：0篇
• 评论：61条
博客专栏
 计算机视觉-人体姿态识别 文章：16篇 阅读：987
文章分类
友情链接
阅读排行