[BZOJ1493][NOI2007]项链工厂

25 篇文章 0 订阅
5 篇文章 0 订阅

原题地址

又是一道数据结构神题,卡了一晚上…

写一下其中几个写搓的地方:
1.update()时要clear()左右子树
2.查询完之后要记得把树merge()回去
3.交换操作那里,若i,j相等则直接退出,要不然会出错
4.染色\查询操作L<=R和L>R时split()的范围不同

UPDATE:split()函数里是不需要用到merge()的!这样就可以实现空间O(n lg n)的可持久化了.以后都要按新的写法来写.

AC code:

#include <cstdio>
#include <cstdlib>
#include <ctime>
const int N=1000010;
int n,c,q,tot;
int a[N];

struct nod{
    int  c,lc,rc,sum,siz,tag,fix;
    bool rev;
    nod  *ch[2];    
}*NIL,pool[N];

struct Treap{
    nod *root;

    Treap(){
        root=NIL=&pool[tot++];
        for(int i=1;i<=n;i++) root=merge(root,newnod(a[i]));
    }
    nod* newnod(int c){
        nod *p=&pool[tot++];
        p->c=p->lc=p->rc=c;p->sum=p->siz=1;p->fix=rand()*rand()%N;
        p->ch[0]=p->ch[1]=NIL;
        return p;
    }
    void update(nod *p){
        p->siz=p->ch[0]->siz+p->ch[1]->siz+1;p->lc=p->rc=p->c;p->sum=1;
        clear(p->ch[0]);clear(p->ch[1]);
        if(p->ch[0]!=NIL){
            p->sum+=p->ch[0]->sum;
            if(p->ch[0]->rc==p->c) p->sum--;
            p->lc=p->ch[0]->lc;
        }
        if(p->ch[1]!=NIL){
            p->sum+=p->ch[1]->sum;
            if(p->ch[1]->lc==p->c) p->sum--;
            p->rc=p->ch[1]->rc;
        }
    }
    void clear(nod *p){
        if(p==NIL) return ;
        if(p->rev){
            int tc=p->lc;p->lc=p->rc;p->rc=tc;
            nod *tp=p->ch[0];p->ch[0]=p->ch[1];p->ch[1]=tp;
            p->rev=0;p->ch[0]->rev^=1;p->ch[1]->rev^=1;
        }
        if(p->tag){
            p->c=p->lc=p->rc=p->tag;p->sum=1;
            p->ch[0]->tag=p->ch[1]->tag=p->tag;p->tag=0;
        }
    }
    nod* merge(nod *p1,nod *p2){
        clear(p1);clear(p2);
        if(p1==NIL) return p2;
        if(p2==NIL) return p1;
        if(p1->fix<=p2->fix){
            p2->ch[0]=merge(p1,p2->ch[0]);
            update(p2);
            return p2;
        }
        p1->ch[1]=merge(p1->ch[1],p2);
        update(p1);
        return p1;
    }
    void split(nod *p,nod *&p1,nod *&p2,int k){
        clear(p);
        if(p==NIL){
            p1=p2=NIL;
            return ;
        }
        if(p->ch[0]->siz+1<=k){
            split(p->ch[1],p1,p2,k-p->ch[0]->siz-1);
            p->ch[1]=p1;
            update(p);
            p1=p;
        }
        else{
            split(p->ch[0],p1,p2,k);
            p->ch[0]=p2;
            update(p);
            p2=p;
        }
    }
    void work1(int k){
        nod *p1,*p2;
        split(root,p1,p2,n-k);
        root=merge(p2,p1);
    }
    void work2(){
        nod *p1,*p2;
        split(root,p1,p2,1);
        p2->rev^=1;
        root=merge(p1,p2);
    }
    void work3(int L,int R){
        if(L==R) return ;
        if(L>R){int t=L;L=R;R=t;}
        nod *p1,*p2,*p3,*p4,*p5,*p6,*p7,*p8;
        split(root,p1,p6,L-1);
        split(p6,p2,p7,1);
        split(p7,p3,p8,R-L-1);
        split(p8,p4,p5,1);
        root=merge(p1,merge(p4,merge(p3,merge(p2,p5))));
    }
    void work4(int L,int R,int k){
        nod *p1,*p2,*p3,*p4;
        if(L<=R){
            split(root,p1,p4,L-1);
            split(p4,p2,p3,R-L+1);
            p2->tag=k;
        }
        else{
            int t=L;L=R;R=t;
            split(root,p1,p4,L);
            split(p4,p2,p3,R-L-1);
            p1->tag=p3->tag=k;
        }
        root=merge(p1,merge(p2,p3));
    }
    int work5(){
        clear(root);
        if(root->sum==1) return 1;
        int ans=work6(1,n);
        if(root->lc==root->rc) ans--;
        return ans;
    }
    int work6(int L,int R){
        int ans;
        nod *p1,*p2,*p3,*p4;
        if(L<=R){
            split(root,p1,p4,L-1);
            split(p4,p2,p3,R-L+1);
            clear(p2);
            ans=p2->sum;
        }
        else{
            int t=L;L=R;R=t;
            split(root,p1,p4,L);
            split(p4,p2,p3,R-L-1);
            clear(p1);clear(p3);
            ans=p1->sum+p3->sum;
            if(p1->lc==p3->rc) ans--;
        }
        root=merge(p1,merge(p2,p3));
        return ans;
    }
};

int main(){
    scanf("%d%d",&n,&c);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    Treap T;
    scanf("%d",&q);
    for(int i=1;i<=q;i++){
        int L,R,x;
        char s[1<<2];
        scanf("%s",s);
        if(s[0]=='R'){
            scanf("%d",&x);
            T.work1(x);
        }
        else if(s[0]=='F') T.work2();
        else if(s[0]=='S'){
            scanf("%d%d",&L,&R);
            T.work3(L,R);
        }
        else if(s[0]=='P'){
            scanf("%d%d%d",&L,&R,&x);
            T.work4(L,R,x);
        }
        else if(s[0]=='C'&&s[1]=='\0') printf("%d\n",T.work5());
        else{
            scanf("%d%d",&L,&R);
            printf("%d\n",T.work6(L,R));
        }
    }

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值