hdu3436 Queue-jumpers(Splay)

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


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

题意:给你一个长为n的序列,第i个数的编号是i,有3个操作,1:把编号为x的数放到序列最前面;2:询问编号为x的数的位置;3:询问第x个位置上的数的编号。

思路:因为n很大(1e8)所以要先离散化,我们把询问的数字都保存下来,变为一个号数的区间 ,然后其他区间都缩成一个点,那么区间的长度最大就为2*10^5了。然后我们先按照位置建立splay,接着就是是play的经典操作了。

下面写了两种程序,第一种是每次找到编号x的数对应的节点,然后再算,第二种是预先用map映射编号x对应的节点,本质是一样的。

#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<vector>
#include<map>
#include<set>
#include<string>
#include<bitset>
#include<algorithm>
using namespace std;
#define lson th<<1
#define rson th<<1|1
typedef long long ll;
typedef long double ldb;
#define inf 99999999
#define pi acos(-1.0)
#define maxn 200050
#define Key_value ch[ch[root][1]][0]
pair<int,int>question[maxn];
int tot,pos[maxn],s[maxn],e[maxn],qishi[maxn];
int t;

int cnt,rt;
int pre[maxn],ch[maxn][2],sz[maxn],num[maxn];


void Treaval(int x) {
    if(x) {
        Treaval(ch[x][0]);
        printf("结点%2d:左儿子 %2d 右儿子 %2d 父结点 %2d size = %2d ,   num= %2d \n",x,ch[x][0],ch[x][1],pre[x],sz[x],num[x]);
        Treaval(ch[x][1]);
    }
}
void debug() {printf("%d\n",rt);Treaval(rt);}


void newnode(int &x,int father,int qujian)
{
    x=qujian;  //为了方便,这里树上节点的编号就是区间的编号
    pre[x]=father;ch[x][0]=ch[x][1]=0;
    sz[x]=num[x]=e[x]-s[x]+1;
}

void pushup(int x)
{
    sz[x]=sz[ch[x][0] ]+sz[ch[x][1] ]+num[x];
}
void build(int &x,int l,int r,int father)
{
    if(l>r)return;
    int mid=(l+r)/2;
    newnode(x,father,mid);

    build(ch[x][0],l,mid-1,x);
    build(ch[x][1],mid+1,r,x);
    pushup(x);
}

void init()
{
    cnt=rt=0;
    pre[rt]=ch[rt][0]=ch[rt][1]=sz[rt]=0;
    build(rt,1,t,0);
}


void rotate(int x,int p)
{
    int y=pre[x];
    ch[y][!p]=ch[x][p];
    pre[ch[x][p] ]=y;
    if(pre[y])ch[pre[y] ][ch[pre[y] ][1]==y ]=x;
    pre[x]=pre[y];
    ch[x][p]=y;
    pre[y]=x;
    pushup(y);pushup(x);
}
void splay(int x,int goal)
{
    while(pre[x]!=goal){
        if(pre[pre[x] ]==goal){
            rotate(x,ch[pre[x]][0]==x);
        }
        else{
            int y=pre[x];int z=pre[y];
            int p=ch[pre[y] ][0]==y;
            if(ch[y][p]==x )rotate(x,!p);
            else rotate(y,p);
            rotate(x,p);
        }
    }
    if(goal==0)rt=x;
    pushup(x);
}

int get_kthjiedian(int &x,int k)
{
    int t1=sz[ch[x][0] ]+1;
    int t2=sz[ch[x][0] ]+num[x];

    if(k>=t1 && k<=t2)return x;
    if(k<t1)return get_kthjiedian(ch[x][0],k);
    if(k>t2)return get_kthjiedian(ch[x][1],k-t2 );
}
int get_min(int r)
{
    while(ch[r][0])
    {
        r = ch[r][0];
    }
    return r;
}
int get_kthweizhi(int r,int k)
{
    int t  = sz[ch[r][0]];
    if(k <= t)return get_kthweizhi(ch[r][0],k);
    else if(k <= t + num[r]) return s[r] + k - t - 1;
    else return get_kthweizhi(ch[r][1],k - t - num[r]);
}
void del()
{
    if(ch[rt][0]==0 ){
        rt=ch[rt][1];
        pre[rt]=0;
    }
    else{
        int y=ch[rt][0];
        int x=ch[rt][1];
        while(ch[y][1]){
            y=ch[y][1];
        }
        splay(y,rt);
        ch[y][1]=x;
        pre[x]=y;
        rt=y;
        pre[rt]=0;
        pushup(rt);
    }
}

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

int main()
{
    int n,m,i,j,T,c,d,cas=0;
    char str[10];
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&m);
        tot=0;
        for(i=1;i<=m;i++){
            scanf("%s%d",str,&c);
            if(str[0]=='T')question[i]=make_pair(1,c);
            else if(str[0]=='Q')question[i]=make_pair(2,c);
            else question[i]=make_pair(3,c);
            pos[++tot]=c;
        }
        pos[++tot]=1;pos[++tot]=n;
        sort(pos+1,pos+1+tot);
        tot=unique(pos+1,pos+1+tot)-pos-1;

        s[1]=e[1]=pos[1];
        t=1;
        for(i=2;i<=tot;i++){
            if(pos[i]-pos[i-1]>1){
                t++;s[t]=pos[i-1]+1;e[t]=pos[i]-1;
            }
            t++;s[t]=e[t]=pos[i];
        }
        init();
        int qujian;
        printf("Case %d:\n",++cas);
        for(i=1;i<=m;i++){
            c=question[i].first;d=question[i].second;
            if(c==1){
                int r=bin(d);
                splay(r,0);
                del();
                splay(get_min(rt),0);  //这里必须直接把删除的节点放到根节点上,不然会T额。。
                ch[r][0] = 0;
                ch[r][1] = rt;
                pre[rt] = r;
                rt = r;
                pre[rt] = 0;
                num[rt]=e[rt]-s[rt]+1;
                pushup(rt);
            }
            if(c==2){
                qujian=bin(d);
                splay(qujian,0);
                printf("%d\n",sz[ch[rt][0] ]+1);
            }
            else if(c==3){
                printf("%d\n",get_kthweizhi(rt,d));
            }
        }
    }
    return 0;
}


#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<vector>
#include<map>
#include<set>
#include<string>
#include<bitset>
#include<algorithm>
using namespace std;
#define lson th<<1
#define rson th<<1|1
typedef long long ll;
typedef long double ldb;
#define inf 99999999
#define pi acos(-1.0)
#define maxn 900050
#define Key_value ch[ch[root][1]][0]
pair<int,int>question[maxn];
int tot,pos[maxn],s[maxn],e[maxn],qishi[maxn];
int t;
map<int,int>mp;
map<int,int>::iterator it;

int cnt,rt;
int pre[maxn],ch[maxn][2],sz[maxn],num[maxn];


void Treaval(int x) {
    if(x) {
        Treaval(ch[x][0]);
        printf("结点%2d:左儿子 %2d 右儿子 %2d 父结点 %2d size = %2d ,   num= %2d \n",x,ch[x][0],ch[x][1],pre[x],sz[x],num[x]);
        Treaval(ch[x][1]);
    }
}
void debug() {printf("%d\n",rt);Treaval(rt);}


void newnode(int &x,int father)
{
    x=++cnt;
    pre[x]=father;ch[x][0]=ch[x][1]=0;
}

void pushup(int x)
{
    sz[x]=sz[ch[x][0] ]+sz[ch[x][1] ]+num[x];
}
void build(int &x,int l,int r,int father)
{
    if(l>r)return;
    int mid=(l+r)/2;
    newnode(x,father);
    sz[cnt]=num[cnt]=e[mid]-s[mid]+1;
    qishi[cnt]=s[mid];
    if(num[cnt]==1)mp[s[mid]]=cnt;

    build(ch[x][0],l,mid-1,x);
    build(ch[x][1],mid+1,r,x);
    pushup(x);
}

void init()
{
    cnt=rt=0;
    pre[rt]=ch[rt][0]=ch[rt][1]=sz[rt]=0;
    build(rt,1,t,0);
}


void rotate(int x,int p)
{
    int y=pre[x];
    ch[y][!p]=ch[x][p];
    pre[ch[x][p] ]=y;
    if(pre[y])ch[pre[y] ][ch[pre[y] ][1]==y ]=x;
    pre[x]=pre[y];
    ch[x][p]=y;
    pre[y]=x;
    pushup(y);pushup(x);
}
void splay(int x,int goal)
{
    while(pre[x]!=goal){
        if(pre[pre[x] ]==goal){
            rotate(x,ch[pre[x]][0]==x);
        }
        else{
            int y=pre[x];int z=pre[y];
            int p=ch[pre[y] ][0]==y;
            if(ch[y][p]==x )rotate(x,!p);
            else rotate(y,p);
            rotate(x,p);
        }
    }
    if(goal==0)rt=x;
    pushup(x);
}

int get_kthjiedian(int &x,int k)
{
    int t1=sz[ch[x][0] ]+1;
    int t2=sz[ch[x][0] ]+num[x];

    if(k>=t1 && k<=t2)return x;
    if(k<t1)return get_kthjiedian(ch[x][0],k);
    if(k>t2)return get_kthjiedian(ch[x][1],k-t2 );
}

int get_kthweizhi(int &x,int k)
{
    int t1=sz[ch[x][0] ]+1;
    int t2=sz[ch[x][0] ]+num[x];
    if(k>=t1 && k<=t2){
        int ans=qishi[x]+k-t1;
        splay(x,0);
        return ans;
    }
    else if(k<t1)return get_kthweizhi(ch[x][0],k);
    else return get_kthweizhi(ch[x][1],k-t2 );



}

void del()
{
    if(ch[rt][0]==0 ){
        rt=ch[rt][1];
        pre[rt]=0;
    }
    else{
        int y=ch[rt][0];
        int x=ch[rt][1];
        while(ch[y][1]){
            y=ch[y][1];
        }
        splay(y,rt);
        ch[y][1]=x;
        pre[x]=y;
        rt=y;
        pre[rt]=0;
        pushup(rt);
    }
}

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

int main()
{
    int n,m,i,j,T,c,d,cas=0;
    char str[10];
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&m);
        tot=0;
        for(i=1;i<=m;i++){
            scanf("%s%d",str,&c);
            if(str[0]=='T')question[i]=make_pair(1,c);
            else if(str[0]=='Q')question[i]=make_pair(2,c);
            else question[i]=make_pair(3,c);
            pos[++tot]=c;
        }
        pos[++tot]=1;pos[++tot]=n;
        sort(pos+1,pos+1+tot);
        tot=unique(pos+1,pos+1+tot)-pos-1;

        s[1]=e[1]=pos[1];
        t=1;
        for(i=2;i<=tot;i++){
            if(pos[i]-pos[i-1]>1){
                t++;s[t]=pos[i-1]+1;e[t]=pos[i]-1;
            }
            t++;s[t]=e[t]=pos[i];
        }
        init();
        printf("Case %d:\n",++cas);
        for(i=1;i<=m;i++){
            c=question[i].first;d=question[i].second;
            if(c==1){
                int geshu=num[mp[d] ];
                int kaishi=qishi[mp[d] ];
                splay(mp[d],0);
                del();
                splay(get_min(rt),0 );
                cnt++;
                qishi[cnt]=kaishi;
                pre[cnt]=0;num[cnt]=geshu;
                pre[rt]=cnt;
                ch[cnt][0]=0;ch[cnt][1]=rt;
                rt=cnt;
                mp[d]=cnt;
                pushup(rt);
            }
            if(c==2){
                splay(mp[d],0);
                printf("%d\n",sz[ch[rt][0] ]+1);
            }
            else if(c==3){
                printf("%d\n",get_kthweizhi(rt,d));
            }
        }
    }
    return 0;
}


展开阅读全文
©️2020 CSDN 皮肤主题: 技术工厂 设计师: CSDN官方博客 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值