1500: [NOI2005]维修数列(Splay)

经典的题目,包含了Splay常见的操作:区间最值,区间求和,区间翻转,区间改值等。


#include <iostream>
#include <string>
#include <cstring>
#include <cctype>
#include <cstdio>
#include <map>
#include <cmath>
#include <stack>
#include <algorithm>
#define Value ch[ch[root][1]][0]
using namespace std;
typedef long long LL ;
const int maxn=500005;
const int INF=0x3f3f3f3f;
int n;
int a[maxn];
struct Splay
{
    int tot1,tot2,root;
    int s[maxn];
    int sum[maxn],pre[maxn],ch[maxn][2],val[maxn];
    int size[maxn],mx[maxn],lx[maxn],rx[maxn],rev[maxn],same[maxn];
    void newNode(int &x,int father,int v)
    {
        if(tot2) x=s[tot2--];
        else x=++tot1;
        ch[x][0]=ch[x][1]=0;
        rev[x]=same[x]=0;
        pre[x]=father;
        size[x]=1;
        val[x]=sum[x]=v;
        lx[x]=rx[x]=mx[x]=v;
    }
    void push_up(int x)
    {
        int ls=ch[x][0],rs=ch[x][1];
        size[x]=size[ls]+size[rs]+1;
        sum[x]=sum[ls]+sum[rs]+val[x];
        lx[x]=max(lx[ls],sum[ls]+val[x]+max(0,lx[rs]));
        rx[x]=max(rx[rs],sum[rs]+val[x]+max(0,rx[ls]));
        mx[x]=max(0,rx[ls])+val[x]+max(lx[rs],0);
        mx[x]=max(mx[x],max(mx[ls],mx[rs]));
    }
    void do_rev(int x)
    {
        if(!x) return ;
        swap(ch[x][0],ch[x][1]);
        swap(lx[x],rx[x]);
        rev[x]^=1;
    }
    void do_same(int x,int v)
    {
        if(!x) return ;
        val[x]=v;
        sum[x]=size[x]*v;
        lx[x]=rx[x]=mx[x]=max(v,sum[x]);
        same[x]=1;
    }
    void do_erase(int x)
    {
        if(!x) return ;
        s[++tot2]=x;
        do_erase(ch[x][0]);
        do_erase(ch[x][1]);
    }
    void push_down(int x)
    {
        if(same[x])
        {
            same[x]=0;
            do_same(ch[x][0],val[x]);
            do_same(ch[x][1],val[x]);
        }
        if(rev[x])
        {
            rev[x]=0;
            do_rev(ch[x][0]);
            do_rev(ch[x][1]);
        }
    }
    void rotate(int x,int kind)
    {
        int y=pre[x];
        push_down(y);
        push_down(x);
        ch[y][!kind]=ch[x][kind];
        pre[ch[x][kind]]=y;
        if(pre[y])
            ch[pre[y]][ch[pre[y]][1]==y]=x;
        pre[x]=pre[y];
        ch[x][kind]=y;
        pre[y]=x;
        push_up(y);
    }
    void adjust(int x,int g)
    {
        while(pre[x]!=g)
        {
            if(pre[pre[x]]==g)
            {
                rotate(x,ch[pre[x]][0]==x);
            }
            else
            {
                int y=pre[x];
                int kind=ch[pre[y]][0]==y;
                if(ch[y][kind]==x)
                {
                    rotate(x,!kind);
                    rotate(x,kind);
                }
                else
                {
                    rotate(y,kind);
                    rotate(x,kind);
                }
            }
        }
        push_up(x);
        if(g==0)
            root=x;
    }
    int getKth(int x,int k)
    {
        push_down(x);
        int t=size[ch[x][0]]+1;
        if(t==k)
            return x;
        else if(k<t)
            return getKth(ch[x][0],k);
        else
            return getKth(ch[x][1],k-t);
    }
    void update_erase(int l,int r)
    {
        adjust(getKth(root,l),0);
        adjust(getKth(root,l+r+1),root);
        do_erase(Value);
        pre[Value]=0;
        Value=0;
        push_up(ch[root][1]);
        push_up(root);
    }
    void update_rev(int l,int r)
    {
        adjust(getKth(root,l),0);
        adjust(getKth(root,l+r+1),root);
        do_rev(Value);
        push_up(ch[root][1]);
        push_up(root);
    }
    void update_same(int l,int r,int v)
    {
        adjust(getKth(root,l),0);
        adjust(getKth(root,l+r+1),root);
        do_same(Value,v);
        push_up(ch[root][1]);
        push_up(root);
    }
    void update_insert(int pos,int nn)
    {
        adjust(getKth(root,pos+1),0);
        adjust(getKth(root,pos+2),root);
        for(int i=0; i<nn; ++i)
            scanf("%d",&a[i]);
        build(Value,0,nn-1,ch[root][1]);
        push_up(ch[root][1]);
        push_up(root);
    }
    int get_Sum(int l,int r)
    {
        adjust(getKth(root,l),0);
        adjust(getKth(root,l+r+1),root);
        return sum[Value];
    }
    int get_Max(int l,int r)
    {
        adjust(getKth(root,l),0);
        adjust(getKth(root,l+r+1),root);
        return mx[Value];
    }
    void init()
    {
        root = tot1 = tot2 = 0;
        ch[root][0] = ch[root][1] = size[root] = pre[root] = 0;
        same[root] = rev[root] = sum[root] = val[root] = 0;
        lx[root] = rx[root] = mx[root] = -INF;
        newNode(root,0,-1);
        newNode(ch[root][1],root,-1);
        for(int i=0; i<n; ++i)
            scanf("%d",&a[i]);
        build(Value,0,n-1,ch[root][1]);
        push_up(ch[root][1]);
        push_up(root);
    }
    void build(int &x,int l,int r,int father)
    {
        if(l>r) return ;
        int m=l+(r-l)/2;
        newNode(x,father,a[m]);
        build(ch[x][0],l,m-1,x);
        build(ch[x][1],m+1,r,x);
        push_up(x);
    }
};
Splay tree;
int main()
{
    int m;
    scanf("%d%d",&n,&m);
    tree.init();
    while(m--)
    {
        char str[20];
        scanf("%s",str);
        if(strcmp(str,"GET-SUM")==0)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            printf("%d\n",tree.get_Sum(x,y));
        }
        else if(strcmp(str,"MAX-SUM")==0)
        {
            int x,y;
            printf("%d\n",tree.get_Max(1,tree.size[tree.root]-2));
        }
        else if(strcmp(str,"INSERT")==0)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            tree.update_insert(x,y);
        }
        else if(strcmp(str,"DELETE")==0)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            tree.update_erase(x,y);
        }
        else if(strcmp(str,"MAKE-SAME")==0)
        {
            int x,y,z;
            scanf("%d%d%d",&x,&y,&z);
            tree.update_same(x,y,z);
        }
        else if(strcmp(str,"REVERSE")==0)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            tree.update_rev(x,y);
        }
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值