Gym 100796J Narrow Bus [splay]

Description

  • The narrow bus is so narrow it doesn't have any seats and the passengers have to stand in a row. The bus has two doors that can be used for entering or leaving the bus: one in the front and one in the back. People can't easily swap in the bus because it is too narrow, so the order people are standing in does not change while the bus is running.

    At each bus stop, either a single person enters the bus or a single person leaves the bus.

    • If a person wants to enter the bus, they will choose one of the doors to do that. Then this person joins the beginning or the end of the row, according to which door they used to enter.
    • If a person wants to leave at a stop, they will choose the direction with the least amount of people and proceed to that door (in case both directions have the same amount of people, the person chooses the front door). Everyone in that direction will have to get out then as well. No one likes standing outside and waiting so everybody who wants to continue riding the bus will use the other door to get back in. These passengers will enter the bus back in the same order they got out.

    Given a description of people entering and leaving the bus, count how many people will have to get out when somebody leaves the bus.

Input

The first line of input contains a single integer n, the number of actions at bus stops (1 ≤ n ≤ 105). The next n lines will contain one of the three types of actions each. The actions happen consecutively as they are given in the input.

  • "F" — a person enters the bus using the front door.
  • "B" — a person enters the bus using the back door.
  • "Oi" — the i-th person that has entered the bus today leaves.

Each action happens at a single bus stop. After the action is completed, the bus leaves for the next stop.

Output

Print a single integer for each type "O" query, the number of people who will have to get out and go back in the bus when a person leaves at the stop.

题意&解法:

模拟一辆车,随时有人会从前门进或者后门进,第I个进来的人编号为I,进来后人们会像一个首尾可进出一样的队列站好,有人要出车辆时,则输出此人两侧中人少的一侧的人的数量,并把这一边的一段数字序列要剪到另一端,这一个过程可以用Splay 实现。

代码:

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
#include<iostream>
#include<stdlib.h>
#include<set>
#include<map>
#include<queue>
#include<vector>
#include<bitset>
#pragma comment(linker, "/STACK:1024000000,1024000000")
template <class T>
bool scanff(T &ret){ //Faster Input
    char c; int sgn; T bit=0.1;
    if(c=getchar(),c==EOF) return 0;
    while(c!='-'&&c!='.'&&(c<'0'||c>'9')) c=getchar();
    sgn=(c=='-')?-1:1;
    ret=(c=='-')?0:(c-'0');
    while(c=getchar(),c>='0'&&c<='9') ret=ret*10+(c-'0');
    if(c==' '||c=='\n'){ ret*=sgn; return 1; }
    while(c=getchar(),c>='0'&&c<='9') ret+=(c-'0')*bit,bit/=10;
    ret*=sgn;
    return 1;
}
#define inf 1073741823
#define llinf 4611686018427387903LL
#define PI acos(-1.0)
#define lth (th<<1)
#define rth (th<<1|1)
#define rep(i,a,b) for(int i=int(a);i<=int(b);i++)
#define drep(i,a,b) for(int i=int(a);i>=int(b);i--)
#define gson(i,root) for(int i=ptx[root];~i;i=ed[i].next)
#define tdata int testnum;scanff(testnum);for(int cas=1;cas<=testnum;cas++)
#define mem(x,val) memset(x,val,sizeof(x))
#define mkp(a,b) make_pair(a,b)
#define findx(x) lower_bound(b+1,b+1+bn,x)-b
#define pb(x) push_back(x)
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;

#define NN 400400
int val[NN],a[NN],c[NN][2],fa[NN],minx[NN],sz[NN];
bool rev[NN];
inline void push(int x){
    int &l=c[x][0],&r=c[x][1];
    if(rev[x]){
        rev[x]=0;rev[l]^=1;rev[r]^=1;
        swap(l,r);
    }
}
inline void update(int x){
    sz[x]=sz[c[x][0]]+sz[c[x][1]]+1;
}
void rotate(int x,int &k){
    int y=fa[x],z=fa[y],l,r;
    l=(c[y][1]==x);r=l^1;
    if(y==k)k=x;
    else c[z][c[z][1]==y]=x;
    fa[y]=x;fa[c[x][r]]=y;fa[x]=z;
    c[y][l]=c[x][r];c[x][r]=y;
    update(y);update(x);
}
void splay(int x,int &k){
    for(push(x);x!=k;){
        int y=fa[x],z=fa[y];
        if(y!=k){
            if(c[y][0]==x^c[z][0]==y)rotate(x,k);
            else rotate(y,k);
        }
        rotate(x,k);
    }
    update(x);
}
void build(int l,int r,int f){
    if(l>r)return;
    int m=(l+r)>>1;
    c[f][m>=f]=m;
    fa[m]=f;
    val[m]=a[m];
    build(l,m-1,m);
    build(m+1,r,m);
    update(m);
}
int findk(int x,int no){
    push(x);
    update(x);
    int l=c[x][0];
    if(sz[l]+1==no)return x;
    if(sz[l]>=no)return findk(l,no);
    return findk(c[x][1],no-sz[l]-1);
}
char op[22];
int n,m,rt,tot;
int getnext(int x){
    splay(x,rt);
    x=c[x][1];
    while(c[x][0]){
        push(x);
        x=c[x][0];
    }
    return x;
}
int getfront(int x){
    splay(x,rt);
    x=c[x][0];
    while(c[x][1]){
        push(x);
        x=c[x][1];
    }
    return x;
}
void init(){
    tot=2;
    rep(i,1,2)c[i][0]=c[i][1]=rev[i]=0;
    build(1,2,0);
    rt=(3)>>1;
}
void insert(int l,int v){
    int x=findk(rt,l);
    int y=findk(rt,l+1);
    splay(x,rt);
    splay(y,c[x][1]);
    c[y][0]=++tot;
    fa[tot]=y;
    sz[tot]=1;
    minx[tot]=val[tot]=v;
    rev[tot]=c[tot][0]=c[tot][1]=0;
    push(y);
    update(y);
    update(x);
}
int main(){
    val[0]=inf;minx[0]=inf;sz[0]=0;
    scanff(n);
    init();
    int idx=0;
    rep(i,1,n){
        scanf("%s",op);
        if(op[0]=='F'){
            idx++;
            insert(1,idx);
        }
        if(op[0]=='B'){
            idx++;
            insert(sz[rt]-1,idx);
        }
        if(op[0]=='O'){
            int x,y;
            scanff(x);
            x+=2;
            splay(x,rt);
            if(sz[c[x][0]]<=sz[c[x][1]]){
                printf("%d\n",sz[c[x][0]]-1);
                y=1;
                splay(y,c[x][0]);
                int z=c[y][1];
                c[y][1]=0;
                update(y);
                update(x);
                int tx=x;
                int x=getfront(tx);
                int y=getnext(tx);
                splay(x,rt);
                splay(y,c[x][1]);
                c[y][0]=0;
                update(y);
                update(x);
                x=findk(rt,sz[rt]-1);
                y=findk(rt,sz[rt]);
                splay(x,rt);
                splay(y,c[x][1]);
                c[y][0]=z;
                fa[z]=y;
                update(y);
                update(x);
            }
            else{
                printf("%d\n",sz[c[x][1]]-1);
                y=2;
                splay(y,c[x][1]);
                int z=c[y][0];
                c[y][0]=0;
                update(y);
                update(x);
                int tx=x;
                int x=getfront(tx);
                int y=getnext(tx);
                splay(x,rt);
                splay(y,c[x][1]);
                c[y][0]=0;
                update(y);
                update(x);
                x=1;
                y=findk(rt,2);
                splay(x,rt);
                splay(y,c[x][1]);
                c[y][0]=z;
                fa[z]=y;
                update(y);
                update(x);
            }
        }
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值