Gym 100796 J. Narrow Bus —— Fhq_treap

This way

题意:

有三种操作:
F 表示一个人到了队首
B 表示一个人到了队尾
O x 表示第x个进来的人找到距离他人最少的出口出去,同时这些挡路的人也出去,并且按顺序从另一个门进来,问你有多少人出去再进来了。

题解:

这种区间平移的题目很明显可以用fhq_treap做,但是每次怎么找到那个人的位置呢,可以在treap中维护每个人的父亲,找当前的人的排名的时候只往需要每次网上跳,如果当前点是父亲的右儿子,那么将父亲的左儿子的siz+1加到位置当中即可。

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int ch[N][3];// 0左孩子 1右孩子
int val[N];// 每一个点的权值
int pri[N];// 随机生成的附件权值
int siz[N];// 以i为节点的树的节点数量
int tot;// 总结点的数量
int to[N];
int fa[N];
mt19937 rnd(time(NULL));
void update(int x){
    siz[x]=1+siz[ch[x][0]]+siz[ch[x][1]];
    if(ch[x][0])fa[ch[x][0]]=x;
    if(ch[x][1])fa[ch[x][1]]=x;
}
unordered_map<int,int>f;
int finds(int x){return f.count(x)?f[x]=finds(f[x]):x;}
int newnode(int v){
    siz[++tot]=1;// 新开辟一个节点
    val[tot]=v;
    to[v]=tot;
    pri[tot]=finds(rnd());
    f[pri[tot]]=finds(pri[tot]+1);
    fa[tot]=tot;
    return tot;
}
int merge(int x,int y){
    if(!x||!y)return x+y;
    if(pri[x]<pri[y]){
        ch[x][1]=merge(ch[x][1],y);
        update(x);
        return x;
    }
    else {
        ch[y][0]=merge(x,ch[y][0]);
        update(y);
        return y;
    }
}
void split(int rt,int k,int &x,int &y){
    if(!rt)x=y=0;
    else {
        if(siz[ch[rt][0]]+1<=k)
            x=rt,split(ch[rt][1],k-siz[ch[rt][0]]-1,ch[rt][1],y);
        else
            y=rt,split(ch[rt][0],k,x,ch[rt][0]);
        update(rt);
    }
}
char s[5];
int main()
{
    srand(unsigned(time(NULL)));
    int n;
    scanf("%d",&n);
    int rt=0,x,all=0;
    for(int i=1;i<=n;i++){
        scanf("%s",s);
        if(s[0]=='O'){
            scanf("%d",&x);
            //x=to[x];
            int now=x,sum=siz[ch[x][0]]+1;
            while(rt!=now){
                if(ch[fa[now]][1]==now)sum+=siz[ch[fa[now]][0]]+1;
                now=fa[now];
            }
            printf("%d\n",min(sum-1,all-sum));
            int r1,r2,r3;
            split(rt,sum,r1,r2);
            split(r1,sum-1,r1,r3);
            rt=merge(r2,r1);
            all--;
        }
        else if(s[0]=='F')
            rt=merge(newnode(i),rt),all++;
        else
            rt=merge(rt,newnode(i)),all++;
    }
    return 0;
}

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值