HDU 3487 Play with Chain

人生第一个splay题。

区间分裂,区间合并还有区间翻转都是比较裸的板子

一个区间分裂成三个区间还是写一个两两分裂的函数比较好写(

区间合并也是

感觉其他也没有什么要针对这个题说的

如果用动态内存的话建议用数组指针,不然会MLE(窝也不造是不是叫这个)

只要splay写好了就能过


以及代码如下


#include<bits\stdc++.h>
using namespace std;

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

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


const int maxn = 312345;
node nodes[maxn];
int tot;

int size(node *o){
    if(o==NULL){
        return 0;
    }
    return o->siz;
}

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

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

void push(node *rot){
    rot->flp=0;
    swap(rot->l,rot->r);
    if(rot->l)
        rot->l->flp ^=1;
    if(rot->r)
        rot->r->flp ^=1;
}

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

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

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{
        printf(" ");
        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 *rot){
    puts("-------------");
    if(!rot)
        puts("NULL!");
    else
        out(rot,0,0);
    puts("=============");
}

node *splite(node *&rot,int x){
    if(x==0){
        node *ret = rot;
        rot=NULL;
        return ret;
    }
    fnd(rot,x);
    node *ret = rot->r;
    rot->r=NULL;
    rot->maintain();
    return ret;
}

node *merg(node* L,node* R){
    if(L){
        fnd(L,L->siz);
        L->r=R;
        L->maintain();
        return L;
    }
    if(R){
        fnd(R,1);
        R->l=L;
        R->maintain();
        return R;
    }
    return NULL;
}



void cut(int L,int R,int C,node* &root){
    node *right=splite(root,R);
    node *left=splite(root,L-1);
    swap(left,root);
    left=merg(left,right);
    right=splite(left,C);
    left=merg(left,root);
    root=merg(left,right);
}


void flip(int L,int R,node* &root){
    node *right=splite(root,R);
    node *left=splite(root,L-1);
    swap(left,root);
    root->flp ^=1 ;
    if(left)
        root=merg(left,root);
    if(right){
        fnd(right,1);
        right->l=root;
        right->maintain();
        root=right;
    }

}




node *build(int n){
    node *root = newnode(1);
    root->maintain();
    for(int i =2;i<=n;i++){
        node *k = newnode(i);
        k->l = root;
        root = k;
        root->maintain();
    }
    return root;
}


int ans[maxn];
int len;

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

int main(){
    int n,m;
    char arr[10];
    while(~scanf("%d %d",&n,&m) && (n+1)||(m+1)){
        tot=0;
        node *root = build(n);
        int L,R,C;
        while(m--){
            scanf("%s %d %d",arr,&L,&R);
            if(arr[0]=='C'){
                scanf("%d",&C);
                cut(L,R,C,root);
           //      print(root);
            }
            else{
                flip(L,R,root);
           //     print(root);
            }
        }
        len=0;
        mid(root);
        for(int i = 0;i<n;i++)
            printf(i<n-1?"%d ":"%d\n",ans[i]);
    }
    return 0;
}


===================================update====================

又写了一发,在右边添加了一个虚拟节点,优化了cut和flip的代码量


node *getseg(int L,int R,node* &root){ //goal is return->l and father is return
    L--,R++;
    if(L){
        fnd(root,L);
        fnd(root->r,R-L);
        return root->r;
    }
    else{
        fnd(root,R);
        return root;
    }
}

void flip(node* &root,int L,int R){
    node * k = getseg(L,R,root);
    k->l->flp ^= 1;
}

void cut(node* &root,int L,int R,int c){
    node * fa = getseg(L,R,root);
    node * k = fa->l;
    fa->l=NULL; fa->maintain();
    root->maintain();
    if(c){
        fnd(root,c);
        fnd(root,c+1);
        root->l->r=k;
        root->l->maintain();
        root->maintain();
    }
    else{
        fnd(root,1);
        root->l=k;
        root->maintain();
    }

}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值