关闭

HDU 3436 Queue-jumpers(Splay)

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

【思路参考】爱神

【解题方法】

仔细分析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;
}



0
0
查看评论

HDU 3436 Queue-jumpers splay

题目链接:HDU 3436 Queue-jumpers  Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total...
  • qq_29480875
  • qq_29480875
  • 2017-09-07 00:12
  • 60

【HDU 3436】Queue-jumpers(Splay)

Splay的基础操作。问题的关键就在于N非常大,就算是利用Splay数组也是远远开不下的,因此很自然地想到了hash一下 可以将所有要进行Top的节点和Query的节点 然后对于每一个节点或者每一个段,可以将它的长度表示出来(方便起见每个点可以看做一个长度为1的线段) 剩下的就是Splay的基础操作...
  • u011332631
  • u011332631
  • 2014-09-13 20:41
  • 390

hdu 3436 Queue-jumpers(Splay)

题目大意: 波妞和加菲猫(这两个角色也能扯到一起)排队的时候无聊玩游戏。 把这个队伍的人从头到尾标号1-n top x操作,把编号为x的人放到对首。 query x操作,x在第几号位置。 rank x操作,x号位置的人的编号是多少。 思路分析: 让你对Splay 的旋转操作的理...
  • u010709592
  • u010709592
  • 2014-01-10 20:13
  • 796

HDU 3436 Queue-jumpers(splay tree)

题意:一开始n个人排除一队, 从1~n, 有三种操作:TOP 把第x个人换到最前面;Query输出第x个人的位置;Rank输出第x个位置的是哪个人。 思路:由于N非常大, 很自然想到先离散化,这题的难点主要就在这里了, 离散化处理得好, 下面就好办了 。 这题要把Top 和Query离散化(这两个...
  • afafsdg
  • afafsdg
  • 2012-09-24 21:16
  • 266

hdu 3436 Queue-jumpers(splay tree)

Queue-jumpers Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 1225 ...
  • zuihoudebingwen
  • zuihoudebingwen
  • 2012-10-11 13:38
  • 613

HDU 3436 Queue-jumpers (Splay tree)

转载请注明出处,谢谢 http://blog.csdn.net/ACM_cxlove?viewmode=contents           by---cxlove 三种操作RAN...
  • ACM_cxlove
  • ACM_cxlove
  • 2012-07-30 09:30
  • 3299

Splay树 + 离散化 —— HDU 3436 Queue-jumpers

Splay树 + 离散化 —— HDU 3436 Queue-jumpers
  • u013351484
  • u013351484
  • 2015-07-14 13:46
  • 558

HDU 3436 Queue-jumpers (Splaytree)

题意:有n个人,编号分别为1~n,从小到大排成一列,有q次操作。 (n Top操作:  把编号为x的人拿出来放到最前面。 Query操作: 问编号为x的人现在在第几个。 Rank操作: 问第x个人编号为多少。 思路:把Top操作和Query操作的所有数离散化下,然后把n个...
  • u010710717
  • u010710717
  • 2014-02-16 17:31
  • 862

HDU 3436 Queue-jumpers splay 离散化 模拟

题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=3436题意:一个序列有N(1<=N<=1e8)N (1 <= N <= 1e8) 个人,起初编号为1的人在序列的第1个位置,2在第2个位置……对这个序列有Q(1<=Q<...
  • dpppBR
  • dpppBR
  • 2017-01-29 21:12
  • 121

hdu 3436 Queue-jumpers

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3436 题目思路:splay,也可以用线段树或树状数组,主要难点在离散化,这个离散化是把点和点这间的区间都离散化,离散化后的点要保存原来区间的长度和起始点等信息,这样就可用splay模拟了,top操作可...
  • Wings_of_Liberty
  • Wings_of_Liberty
  • 2012-07-14 22:56
  • 810
    个人资料
    • 访问:411489次
    • 积分:16482
    • 等级:
    • 排名:第746名
    • 原创:1274篇
    • 转载:21篇
    • 译文:0篇
    • 评论:61条
    博客专栏
    文章分类