BZOJ 1500 [NOI2005]维修数列(splay)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=1500

题意:一个数列,维护以下操作。

思路:以下A代表根节点,B在根节点右子树,C代表根节点右子树的左子树即B的左子树

(1)插入时,将pos-1和pos+cnt分别调至A和B,将插入节点建立一棵子树插在C即可;

(2)删除时,将pos-1和pos+cnt分别调至A和B,将C删掉;本题要回收C的内存才能AC,否则内存占用过大;

(3)修改时,在节点上增加修改的标记,将pos-1和pos+cnt分别调至A和B,将C标记修改;

(4)翻转时,在节点上增加翻转的标记,将pos-1和pos+cnt分别调至A和B,将C标记翻转;

(5)在节点增加sum,将pos-1和pos+cnt分别调至A和B,则C的sum就是所求;

(6)在节点增加maxL,maxR,maxM,将pos-1和pos+cnt分别调至A和B,则C的maxM就是所求。

另外,修改后要及时更新,办法就是每次将C马上调至根节点。对于翻转,向下传递时除了翻转左右孩子外还要翻转maxL和maxR。



struct node
{
    int value,rev,lazy,size,sum,maxL,maxR,maxM;
    int id;
    node* c[2];
    node* p;
};

node a[N],*root,*null;
int n,m,b[N];
queue<int> Q;

node* newNode(int value,node *p)
{
    int id=Q.front();
    Q.pop();
    node *e=&a[id];
    e->id=id;
    e->value=value;
    e->size=1;
    e->p=p;
    e->rev=e->sum=e->lazy=0;
    e->c[0]=e->c[1]=null;
    e->maxL=e->maxR=e->maxM=-INF;
    return e;
}



void pushDown(node *p)
{
    if(p==null) return;
    if(p->rev)
    {
        p->rev=0;
        swap(p->c[0],p->c[1]);
        swap(p->maxL,p->maxR);
        p->c[0]->rev^=1;
        p->c[1]->rev^=1;
    }
    if(p->lazy)
    {
        p->lazy=0;
        p->sum=p->size*p->value;
        if(p->value<=0)
        {
            p->maxL=p->maxR=p->maxM=p->value;
        }
        else
        {
            p->maxL=p->maxR=p->maxM=p->sum;
        }
        p->c[0]->lazy=1;
        p->c[1]->lazy=1;
        p->c[0]->value=p->value;
        p->c[1]->value=p->value;
    }
}



void pushUp(node *p)
{
    if(p==null) return;
    p->size=p->c[0]->size+p->c[1]->size+1;
    p->sum=p->c[0]->sum+p->value+p->c[1]->sum;
    p->maxL=p->c[0]->maxL;
    p->maxL=max(p->maxL,p->c[0]->sum+p->value);
    p->maxL=max(p->maxL,p->c[0]->sum+p->value+p->c[1]->maxL);
    p->maxR=p->c[1]->maxR;
    p->maxR=max(p->maxR,p->c[1]->sum+p->value);
    p->maxR=max(p->maxR,p->c[1]->sum+p->value+p->c[0]->maxR);
    p->maxM=max(p->value,p->sum);
    p->maxM=max(p->maxM,max(p->c[0]->maxM,p->c[1]->maxM));
    p->maxM=max(p->maxM,p->c[0]->maxR+p->value);
    p->maxM=max(p->maxM,p->c[1]->maxL+p->value);
    p->maxM=max(p->maxM,p->c[0]->maxR+p->value+p->c[1]->maxL);
}

void init()
{
    int i;
    for(i=0;i<N;i++) Q.push(i);
    null=0;
    null=newNode(-INF,0);
    null->size=0;
    root=newNode(-INF,null);
    root->c[1]=newNode(-INF,root);
    pushUp(root);
}

void rotate(node *x,int k)
{
    node *y=x->p;
    pushDown(x->c[0]);
    pushDown(x->c[1]);
    pushDown(y->c[!k]);
    y->c[k]=x->c[!k];
    y->c[k]->p=y;
    x->p=y->p;
    if(y->p->c[0]==y) y->p->c[0]=x;
    else y->p->c[1]=x;
    y->p=x;
    x->c[!k]=y;
    pushUp(y);
    pushUp(x);
    if(root==y) root=x;
}



void splay(node *x,node *y)
{
    pushDown(x);
    while(x->p!=y)
    {
        if(x->p->p==y)
        {
            if(x->p->c[0]==x) rotate(x,0);
            else rotate(x,1);
        }
        else if(x->p->p->c[0]==x->p)
        {
            if(x->p->c[0]==x) rotate(x->p,0);
            else rotate(x,1);
            rotate(x,0);
        }
        else
        {
            if(x->p->c[1]==x) rotate(x->p,1);
            else rotate(x,0);
            rotate(x,1);
        }
    }
}


void select(int k,node *y)
{
    node *x=root;
    pushDown(x);
    while(k!=x->c[0]->size+1)
    {
        if(k<x->c[0]->size+1) x=x->c[0];
        else
        {
            k-=x->c[0]->size+1;
            x=x->c[1];
        }
        pushDown(x);
    }
    splay(x,y);
}

void build(int L,int R,int b[],node *p,int side)
{
    if(L>R) return;
    int mid=(L+R)>>1;
    node *x=newNode(b[mid],p);
    p->c[side]=x;
    build(L,mid-1,b,x,0);
    build(mid+1,R,b,x,1);
    pushUp(x);
}


void insert(int pos,int cnt,int b[])
{
    select(pos+1,null);
    select(pos+2,root);
    build(1,cnt,b,root->c[1],0);
    splay(root->c[1]->c[0],null);
}


queue<int> q;

void del(int pos,int cnt)
{
    select(pos,null);
    select(pos+cnt+1,root);
    q.push(root->c[1]->c[0]->id);
    root->c[1]->c[0]=null;
    splay(root->c[1],null);

    int u;
    node *p;
    while(!q.empty())
    {
        u=q.front();
        q.pop();

        Q.push(u);
        p=&a[u];
        if(p->c[0]!=null) q.push(p->c[0]->id);
        if(p->c[1]!=null) q.push(p->c[1]->id);
    }
}


void reverse(int pos,int cnt)
{
    select(pos,null);
    select(pos+cnt+1,root);
    root->c[1]->c[0]->rev^=1;
    splay(root->c[1]->c[0],null);
}

void makesame(int pos,int cnt,int value)
{
    select(pos,null);
    select(pos+cnt+1,root);
    root->c[1]->c[0]->lazy=1;
    root->c[1]->c[0]->value=value;
    splay(root->c[1]->c[0],null);
}

int getsum(int pos,int cnt)
{
    select(pos,null);
    select(pos+cnt+1,root);
    return root->c[1]->c[0]->sum;
}

int getmaxsum(int pos,int cnt)
{
    select(pos,null);
    select(pos+cnt+1,root);
    return root->c[1]->c[0]->maxM;
}


int main()
{
    init();
    scanf("%d%d",&n,&m);
    int i,x,y,z;
    char op[15];
    for(i=1;i<=n;i++) scanf("%d",b+i);
    insert(0,n,b);
    while(m--)
    {
        scanf("%s",op);
        if(op[0]=='I')
        {
            scanf("%d%d",&x,&y);
            for(i=1;i<=y;i++) scanf("%d",b+i);
            insert(x,y,b);
            n+=y;
        }
        else if(op[0]=='D')
        {
            scanf("%d%d",&x,&y);
            del(x,y);
            n-=y;
        }
        else if(op[0]=='M'&&op[2]=='K')
        {
            scanf("%d%d%d",&x,&y,&z);
            makesame(x,y,z);
        }
        else if(op[0]=='R')
        {
            scanf("%d%d",&x,&y);
            reverse(x,y);
        }
        else if(op[0]=='G')
        {
            scanf("%d%d",&x,&y);
            printf("%d\n",getsum(x,y));
        }
        else
        {
            printf("%d\n",getmaxsum(1,n));
        }
    }
    return 0;
}

  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值