BZOJ 1500 【NOI2005 D1T2】 维修数列 Splay

题目大意:维护一个数列支持以下操作:
这里写图片描述

这个Splay有毒,抄模板请参照这里

Splay裸题
可啪(?)的题,细节真的很重要
parent指针好像乱七八糟的样子,但是没用上…
在maintain操作前要先pushdown把标记推下去(标记也修改自己,不推标记的话不能保证信息的正确性)
子段和也要用自己的权值去更新

这俩错误查一天…

#include <cstdio>
#include <algorithm>
#define INF 500000001
#define Max(a,b) (a>b?a:b)
using namespace std;
int n,m,a[500005];
struct Node{
    Node *ch[2],*pa;
    int v,s,lmax,rmax,sum,maxs,fix;
    bool flip,change;
    Node(int);
    int cmp(int x){
        if(x==ch[0]->s+1) return -1;
        return x < ch[0]->s+1 ? 0 : 1;
    }
    void maintain();
    void pushdown();
}*null,*root;
void Node :: maintain(){
    ch[0]->pushdown(); ch[1]->pushdown();
    s=ch[0]->s+ch[1]->s+1;
    sum=ch[0]->sum+ch[1]->sum+v;
    lmax=Max(ch[0]->lmax,ch[0]->sum+v); lmax=Max(lmax,ch[0]->sum+v+ch[1]->lmax);
    rmax=Max(ch[1]->rmax,ch[1]->sum+v); rmax=Max(rmax,ch[1]->sum+v+ch[0]->rmax);
    maxs=Max(ch[0]->maxs,ch[1]->maxs); maxs=Max(maxs,v);
    maxs=Max(ch[0]->rmax+v,maxs); maxs=Max(ch[1]->lmax+v,maxs); maxs=Max(ch[0]->rmax+v+ch[1]->lmax,maxs);
    return ;
}
void Node :: pushdown(){
    if(this==null) return ;
    if(change){
        change=false;
        ch[0]->change=ch[1]->change=true;
        ch[0]->fix=ch[1]->fix=fix;
        sum=s*fix;
        v=fix;
        if(fix>0)lmax=rmax=maxs=sum;
        else lmax=rmax=maxs=fix;
    }
    if(flip){
        flip=false;
        swap(ch[0],ch[1]);
        swap(lmax,rmax);
        ch[0]->flip=!ch[0]->flip;
        ch[1]->flip=!ch[1]->flip;
    }
    return ;
}
Node :: Node(int v=0):v(v){
    pa=ch[0]=ch[1]=null; flip=change=false;
    if(!null){
        lmax=rmax=maxs=-INF;
        sum=0;
        s=0;
    }
    else maintain();
}
void init(Node*& o,int l,int r){
    int mid=(l+r)>>1;
    if(l>r){
        o=null;
        return ;
    }
    o=new Node(a[mid]);
    init(o->ch[0],l,mid-1); init(o->ch[1],mid+1,r);
    if(o->ch[0]!=null) o->ch[0]->pa=o;
    if(o->ch[1]!=null) o->ch[1]->pa=o;
    o->maintain();
    return ;
}
void Rotate(Node*& o,int d){
    Node* k=o->ch[d^1];
    o->ch[d^1]=k->ch[d]; k->ch[d]->pa=o;
    k->ch[d]=o; k->pa=o->pa; o->pa=k;
    o->maintain(); k->maintain();
    o=k;
    return ;
}
void Splay(Node*& o,int k){
    o->pushdown();
    int d=o->cmp(k);
    if(d==1) k-=o->ch[0]->s+1;
    if(d!=-1){
        Node* p=o->ch[d];
        p->pushdown();
        int d2=p->cmp(k);
        if(d2==1) k-=p->ch[0]->s+1;
        if(d2!=-1){
            Splay(p->ch[d2],k);
            if(d==d2) Rotate(o,d^1);
            else Rotate(o->ch[d],d);
        }
        Rotate(o,d^1);
    }
    return ;
}
Node* Merge(Node* l,Node* r){
    if(l==null) return r;
    Splay(l,l->s);
    l->ch[1]=r;
    r->pa=l;
    l->maintain();
    return l;
}
void Split(Node* o,int k,Node*& l,Node*& r){
    if(!k){
        l=null;
        r=o;
        return ;
    }
    Splay(o,k);
    l=o;
    r=o->ch[1];
    o->ch[1]=null;
    l->maintain();
    return ;
}
void Delete(Node*& o){
    if(o->ch[0]!=null) Delete(o->ch[0]);
    if(o->ch[1]!=null) Delete(o->ch[1]);
    delete o;
    o=null;
    return ;
}
int main(){
    freopen("a.in","r",stdin); freopen("a.out","w",stdout);
    null=new Node();
    null->ch[0]=null->ch[1]=null->pa=null;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    init(root,1,n);
    while(m--){
        char c[10];
        scanf("%s",c);
        if(c[0]=='I'){//Insert
            int pos,tot;
            scanf("%d%d",&pos,&tot);
            for(int i=1;i<=tot;i++) scanf("%d",&a[i]);
            Node *o,*l,*r;
            init(o,1,tot);
            Split(root,pos,l,r);
            root=Merge(Merge(l,o),r);
        }
        else if(c[0]=='D'){//Delete
            int pos,tot;
            scanf("%d%d",&pos,&tot);
            Node *mid,*l,*r,*o;
            Split(root,pos-1,l,o);
            Split(o,tot,mid,r);
            Delete(mid);
            root=Merge(l,r);
        }
        else if(c[0]=='R'){//Reverse
            int pos,tot;
            scanf("%d%d",&pos,&tot);
            Node *mid,*l,*r,*o;
            Split(root,pos-1,l,o);
            Split(o,tot,mid,r);
            mid->flip=true;
            root=Merge(Merge(l,mid),r);
        }
        else if(c[0]=='G'){//GET-SUM
            int pos,tot;
            scanf("%d%d",&pos,&tot);
            if(!tot){
                printf("0\n");
                continue;
            }
            Node *mid,*l,*r,*o;
            Split(root,pos-1,l,o);
            Split(o,tot,mid,r);
            printf("%d\n",mid->sum);
            root=Merge(Merge(l,mid),r);
        }
        else if(c[2]=='X'){//MAX-SUM
            printf("%d\n",root->maxs);
        }
        else {//MAKE-SAME
            int pos,tot,cach;
            scanf("%d%d%d",&pos,&tot,&cach);
            Node *mid,*l,*r,*o;
            Split(root,pos-1,l,o);
            Split(o,tot,mid,r);
            mid->change=true;
            mid->fix=cach;
            root=Merge(Merge(l,mid),r);
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值