Poj 2828 Buy Tickets

一个线段树加点思维的题目

被窝用splay水过去了Orz

(其实我也不想的,只是正好刚学splay,就看到一个动态插入的题,就。。。就没忍住Orz


用splay写就不用什么思维了,我的思路是给这个队列加上一个虚拟的最后一人来处理刚开始一个人都没有的时候插入的情况

这样写还可以在之后插入的时候无脑插在左边,不用担心没有右边的节点的情况,大概就酱


以及代码如下


#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

#define l ch[0]
#define r ch[1]

struct node{
    int val,siz;
    node * ch[2];
    void maintain(){
        siz = 1;
        if(l) siz+=l->siz;
        if(r) siz+=r->siz;
    }
};

int siz(node * o){
    if(!o)
        return 0;
    return o->siz;
}

const int maxn = 212345;

node nodes[maxn];
int tot;

void out(node * rot,int d,int k){
    if(rot->r)
        out(rot->r,d+1,-1);
    for(int i=0;i<d;i++)
        printf("  ");
    if(k==0)
        printf("--");
    else{
        if(k==-1) printf("/");
        else printf("\\");
    }
    printf("%d ( %d )\n",rot->val,rot->siz);
    if(rot->l)
        out(rot->l,d+1,1);
}

void print(node * root){
    out(root,0,0);
}

node * newnode(int x){
    node * ret = &nodes[tot++];
    ret->val = x;
    ret->siz = 1;
    ret->l=ret->r=NULL;
    return ret;
}

void zg(node* &o,int d){
    node * k = o->ch[d];
    o->ch[d]=k->ch[d^1];
    k->ch[d^1]=o;
    o=k;
    o->maintain();
    o->ch[d^1]->maintain();
}

int splay(node* &rot,int x){
    int p = siz(rot->l)+1;
    if(p==x)
        return 2;
    int d = p > x ? 0 : 1;
    if(d) x-=p;
    int k = splay(rot->ch[d],x);
    if(k==2)
        return d;
    if(k==d) zg(rot,k);
    else zg(rot->ch[d],k);
    zg(rot,d);
    return 2;
}

void fnd(node* &rot,int x){
    int k = splay(rot,x);
    if(k!=2)
        zg(rot,k);
}

void inser(int val,int lo,node* &root){
    node * k = newnode(val);
    lo++;
    if(lo==1){
        fnd(root,1);
        root->l = k;
        root->maintain();
    }
    else{
        fnd(root,lo-1);
        fnd(root,lo);
        root->l->r = k;
        root->l->maintain();
        root->maintain();
    }
}

int ans[maxn];
int len;

void mid(node *rot){
    if(rot->l)
        mid(rot->l);
    ans[len++]=rot->val;
    if(rot->r)
        mid(rot->r);
}


int main(){
    int n;
    while(~scanf("%d",&n)){
        tot = 0;
        node *rot = newnode(0);
        int x,pos;
        for(int i=1;i<=n;i++){
            scanf("%d %d",&pos,&x);
         //   print(rot);
            inser(x,pos,rot);
        }
        len = 0;
        mid(rot);
        for(int i=0;i<n;i++)
            printf(i<n-1?"%d ":"%d\n",ans[i]);
    }
    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值