【bzoj1500】[NOI2005]维修数列 Splay

Description

这里写图片描述

Input

输入文件的第1行包含两个数N和M,N表示初始时数列中数的个数,M表示要进行的操作数目。第2行包含N个数字,描述初始时的数列。以下M行,每行一条命令,格式参见问题描述中的表格。

Output

对于输入数据中的GET-SUM和MAX-SUM操作,向输出文件依次打印结果,每个答案(数字)占一行。

Sample Input

9 8

2 -6 3 5 1 -5 -3 6 3

GET-SUM 5 4

MAX-SUM

INSERT 8 3 -5 7 2

DELETE 12 1

MAKE-SAME 3 3 2

REVERSE 3 6

GET-SUM 5 4

MAX-SUM

Sample Output

-1

10

1

10

HINT

这里写图片描述

Source

Splay


前五种是基本操作。

对于第六种,多保存几个值。当前区间包含左端点的答案lx,包含右端点的答案rx,整个区间的答案mx。这样就能向上更新。跟线段树的做法一样,不说了。

不过要注意细节,两个新加节点向上更新的时候不要影响结果,因为答案可能是负数所以要初始化为-INF。

区间反转要交换当前点的lx和rx。

本题空间吃紧,要回收空间,所以删除操作变得很慢(要一个点一个点删除)。把删除的点的空间压入栈内,然后取栈中元素继续利用。

不得不说恶心人的splay可以告一段落了,这题模板题可以一天一遍233

代码:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;

const int SZ = 1000010;
const int INF = 1000000010;

struct node{
    node *f,*ch[2];
    int v,sz,cnt,sum,lx,rx,mx;
    bool same,rev;

    void setc(node *x,int d) { (ch[d] = x) -> f = this; }
    int dir() { return f -> ch[1] == this; }
    void pushdown();
    void maintain()
    {
        sz = ch[0] -> sz + ch[1] -> sz + cnt;
        sum = ch[0] -> sum + ch[1] -> sum + v;
        lx = max(ch[0] -> lx,ch[0] -> sum + v + max(ch[1] -> lx,0));
        rx = max(ch[1] -> rx,ch[1] -> sum + v + max(ch[0] -> rx,0));
        mx = max(max(ch[0] -> mx,ch[1] -> mx),max(ch[0] -> rx,0) + v + max(ch[1] -> lx,0));
    }
}T[SZ], *root, *null;

int sa[SZ],Tcnt1 = 0,Tcnt2 = 0;

int num[SZ];

node* newnode(int v,node *f)
{
    int cnt;
    if(Tcnt2) cnt = sa[Tcnt2 --];
    else cnt = Tcnt1++;
    node *k = T + cnt;
    k -> ch[0] = k -> ch[1] = null;
    k -> f = f;
    k -> v = k -> sum = k -> lx = k -> rx = k -> mx = v;
    k -> sz = k -> cnt = 1;
    k -> same = k -> rev = 0;
    return k;
}

void pushdrev(node *p)
{
    if(p == null) return ;
    swap(p -> ch[0],p -> ch[1]);
    swap(p -> lx,p -> rx);
    p -> rev ^= 1;
}

void pushdsame(node *p,int v)
{
    if(p == null) return ;
    p -> same = 1;
    p -> sum = v * p -> sz;
    p -> v = v;
    p -> mx = p -> lx = p -> rx = max(v,p -> sum);
}

void node::pushdown()
{
    if(this == null) return ;
    if(rev)
    {
        pushdrev(ch[0]);
        pushdrev(ch[1]);
        rev = 0;
    }
    if(same)
    {
        pushdsame(ch[0],v);
        pushdsame(ch[1],v);
        same = 0;
    }
}

void rotate(node *p)
{
    node *fa = p -> f;
    int d = p -> dir();
    fa -> f -> setc(p,fa -> dir());
    fa -> setc(p -> ch[d ^ 1],d); fa -> maintain();
    p -> setc(fa,d ^ 1); p -> maintain();
    if(fa == root) root = p;
}

void splay(node *p,node *rt = null)
{
    p -> pushdown();
    while(p -> f != rt)
    {
        if(p -> f -> f == rt) rotate(p);
        else
        {
            p -> f -> f -> pushdown(); p -> f -> pushdown(); p -> pushdown();
            if(p -> dir() == p -> f -> dir()) rotate(p -> f),rotate(p);
            else rotate(p),rotate(p);
        }
    }
    p -> maintain();
}

node* find(node *p,int k)
{
    while(p != null)
    {
        p -> pushdown();
        int l = p -> ch[0] -> sz + 1; 
        int r = p -> ch[0] -> sz + p -> cnt;
        if(l <= k && k <= r) return p;
        if(k > r) k -= r,p = p -> ch[1];
        else p = p -> ch[0]; 
    }
}

void build(node* &p,int l,int r,node *fa)
{
    if(l > r) return ;
    int mid = (l + r) >> 1;
    p = newnode(num[mid],fa);
    build(p -> ch[0],l,mid - 1,p);
    build(p -> ch[1],mid + 1,r,p);
    p -> maintain();
}

void insert(int pos,int tot)
{
    pos ++;
    for(int i = 1;i <= tot;++ i) scanf("%d",&num[i]);
    splay(find(root,pos)); splay(find(root,pos + 1),root);
    build(root -> ch[1] -> ch[0],1,tot,root -> ch[1]);
    root -> ch[1] -> maintain();
    root -> maintain();
}

void dfs(node *p)
{
    if(p == null) return ;
    sa[++ Tcnt2] = p - T;
    dfs(p -> ch[0]);
    dfs(p -> ch[1]);
}

void erase(int l,int r)
{
    l ++,r ++;
    splay(find(root,l - 1));    splay(find(root,r + 1),root);
    dfs(root -> ch[1] -> ch[0]);
    root -> ch[1] -> ch[0] = null;
    root -> ch[1] -> maintain();
    root -> maintain();
}

void change(int l,int r,int v)
{
    l ++,r ++;
    splay(find(root,l - 1));    splay(find(root,r + 1),root);
    pushdsame(root -> ch[1] -> ch[0],v);
    root -> ch[1] -> maintain();
    root -> maintain(); 
}

void reverse(int l,int r)
{
    l ++,r ++;
    splay(find(root,l - 1));    splay(find(root,r + 1),root);
    pushdrev(root -> ch[1] -> ch[0]);
    root -> ch[1] -> maintain();
    root -> maintain(); 
}

int ask_sum(int l,int r)
{
    l ++,r ++;
    splay(find(root,l - 1));    splay(find(root,r + 1),root);
    return root -> ch[1] -> ch[0] -> sum;
}


int ask_ans(int l,int r)
{
    l ++,r ++;
    splay(find(root,l - 1));    splay(find(root,r + 1),root);
    return root -> ch[1] -> ch[0] -> mx;
}

void init()
{
    null = newnode(-INF,null);
    null -> cnt = null -> sz = 0;

    root = newnode(-INF,null);
    root -> ch[1] = newnode(-INF,root);
    root -> sum = null -> sum = root -> ch[1] -> sum = 0;
    root -> maintain();
}

int main()
{
    freopen("sequence.in","r",stdin); 
    freopen("sequence.out","w",stdout);     
    int n,m;
    scanf("%d%d",&n,&m);
    init();
    insert(0,n);

    while(m --)
    {
        char in[20];
        scanf("%s",in);
        if(in[2] == 'S')
        {
            int pos,tot;
            scanf("%d%d",&pos,&tot); 
            insert(pos,tot);
        }
        else if(in[2] == 'L')
        {
            int pos,tot;
            scanf("%d%d",&pos,&tot);
            int l = pos,r = pos + tot - 1;
            erase(l,r);
        }
        else if(in[2] == 'K')
        {
            int pos,tot,c;
            scanf("%d%d%d",&pos,&tot,&c);
            int l = pos,r = pos + tot - 1;
            change(l,r,c);
        }
        else if(in[2] == 'V')
        {
            int pos,tot;
            scanf("%d%d",&pos,&tot);
            int l = pos,r = pos + tot - 1;
            reverse(l,r);       
        }
        else if(in[2] == 'T')
        {
            int pos,tot;
            scanf("%d%d",&pos,&tot);
            int l = pos,r = pos + tot - 1;          
            printf("%d\n",ask_sum(l,r));
        }
        else
        {
            printf("%d\n",ask_ans(1,root -> sz  - 2));          
        }
    }
    return 0;   
}



12.30:
今天换了种打法,把splay的各种操作放到一个结构体里了,这样以后维护多棵splay就方便许多,码量也并没有加几行

需要注意的是需要先初始化null

代码:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;

const int SZ = 1000010;
const int INF = 1000000010;

struct node{
    node *ch[2],*f;
    int sz,v,cnt,sum,lx,rx,mx;
    bool same,rev;

    void maintain()
    {
        sz = ch[0] -> sz + ch[1] -> sz + cnt;
        sum = ch[0] -> sum + ch[1] -> sum + v;
        lx = max(ch[0] -> lx,ch[0] -> sum + v + max(0,ch[1] -> lx));
        rx = max(ch[1] -> rx,ch[1] -> sum + v + max(0,ch[0] -> rx));
        mx = max(max(ch[0] -> mx,ch[1] -> mx),max(0,ch[0] -> rx) + v + max(0,ch[1] -> lx));
    }
    void pushdown();
    void setc(node *x,int d) { (ch[d] = x) -> f = this; }
    int dir() { return f -> ch[1] == this; }
}T[SZ], *null;

int sa[SZ],Tcnt1 = 0,Tcnt2 = 0;

node* newnode(int x,node *fa)
{
    int cnt;
    if(Tcnt2) cnt = sa[Tcnt2 --];
    else cnt = Tcnt1 ++;
    node *k = T + cnt;
    k -> ch[0] = k -> ch[1] = null;
    k -> v = k -> lx = k -> rx = k -> mx = k -> sum = x;
    k -> sz = k -> cnt = 1;
    k -> f = fa;
    k -> same = k -> rev = 0;
    return k;
}

void pushsame(node *p,int v)
{
    if(p == null) return ;
    p -> v = v;
    p -> sum = v * p -> sz;
    p -> mx = p -> lx = p -> rx = max(v,p -> sum);
    p -> same = 1;
}

void pushrev(node *p)
{
    if(p == null) return ;
    swap(p -> ch[0],p -> ch[1]);
    swap(p -> lx,p -> rx);
    p -> rev ^= 1;
}

void node :: pushdown()
{
    if(same)
    {
        pushsame(ch[0],v); pushsame(ch[1],v);
        same = 0;
    }
    if(rev)
    {
        pushrev(ch[0]); pushrev(ch[1]);
        rev = 0;
    }
}

int num[SZ];

struct Splaytree{
    node *root;

    Splaytree() 
    {
        root = newnode(-INF,null);
        root -> ch[1] = newnode(-INF,root);
        root -> ch[1] -> maintain();        
        root -> maintain();     
    }

    void rotate(node *p)
    {
        node *fa = p -> f;
        int d = p -> dir();
        fa -> f -> setc(p,fa -> dir());
        fa -> setc(p -> ch[d ^ 1],d); fa -> maintain();
        p -> setc(fa,d ^ 1); p -> maintain();
        if(fa == root) root = p;
    }

    void splay(node *p,node *rt = null)
    {
        p -> pushdown();
        while(p -> f != rt)
        {
            if(p -> f -> f == rt) rotate(p);
            else
            {
                p -> f -> f -> pushdown(); p -> f -> pushdown(); p -> pushdown();
                if(p -> dir() == p -> f -> dir()) rotate(p -> f),rotate(p); 
                else rotate(p),rotate(p);
            }
        }
        p -> maintain();
    }

    node* find(node *p,int k)
    {
        while(p != null)
        {
            p -> pushdown();
            int l = p -> ch[0] -> sz + 1;
            int r = p -> ch[0] -> sz + p -> cnt;
            if(l <= k && k <= r) return p;
            if(k > r) k -= r,p = p -> ch[1];
            else p = p -> ch[0];
        }
    }

    void build(node* &p,int l,int r,node *fa)
    {
        if(l > r) return ;
        int mid = (l + r) >> 1;
        p = newnode(num[mid],fa);
        build(p -> ch[0],l,mid - 1,p);
        build(p -> ch[1],mid + 1,r,p);
        p -> maintain();
    }

    void insert(int pos,int tot)
    {
        for(int i = 1;i <= tot;i ++) scanf("%d",&num[i]);
        splay(find(root,pos + 1)); splay(find(root,pos + 2),root);
        build(root -> ch[1] -> ch[0],1,tot,root -> ch[1]);
        root -> ch[1] -> maintain();
        root -> maintain();
    }

    void del(node *p)
    {
        if(p == null) return ;
        sa[++ Tcnt2] = p - T;
        del(p -> ch[0]);
        del(p -> ch[1]);
    }

    void erase(int pos,int tot)
    {
        splay(find(root,pos)); splay(find(root,pos + tot + 1),root);
        del(root -> ch[1] -> ch[0]);
        root -> ch[1] -> ch[0] = null;
        root -> ch[1] -> maintain();
        root -> maintain();
    }

    void change(int pos,int tot,int v)
    {
        splay(find(root,pos)); splay(find(root,pos + tot + 1),root);
        pushsame(root -> ch[1] -> ch[0],v);
        root -> ch[1] -> maintain();
        root -> maintain();
    }   

    void reverse(int pos,int tot)
    {
        splay(find(root,pos)); splay(find(root,pos + tot + 1),root);
        pushrev(root -> ch[1] -> ch[0]);
        root -> ch[1] -> maintain();
        root -> maintain();
    }   

    int ask_sum(int pos,int tot)
    {
        splay(find(root,pos)); splay(find(root,pos + tot + 1),root);
        return root -> ch[1] -> ch[0] -> sum;
    }       

    int ask_ans()
    {
        return root -> mx;
    }   

};

void init()
{
    null = newnode(-INF,null);
    null -> sum = 0;
    null -> sz = null -> cnt = 0;
}

int main()
{   
    freopen("sequence.in","r",stdin);
    freopen("sequence.out","w",stdout);
    int n,m;
    scanf("%d%d",&n,&m);
    init();

    Splaytree s;

    s.insert(0,n);
    while(m --)
    {
        char opt[10];
        int pos,tot;
        scanf("%s",opt);
        if(opt[2] == 'S')
        {
            scanf("%d%d",&pos,&tot);
            s.insert(pos,tot);
        }
        else if(opt[2] == 'L')
        {
            scanf("%d%d",&pos,&tot);
            s.erase(pos,tot);        
        }
        else if(opt[2] == 'K')
        {
            int v;
            scanf("%d%d%d",&pos,&tot,&v);
            s.change(pos,tot,v);          
        }      
        else if(opt[2] == 'V')
        {
            scanf("%d%d",&pos,&tot);
            s.reverse(pos,tot);            
        }
        else if(opt[2] == 'T')
        {
            scanf("%d%d",&pos,&tot);
            printf("%d\n",s.ask_sum(pos,tot));      
        }      
        else
        {
            printf("%d\n",s.ask_ans());        
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值