【洛谷 P2042】 [NOI2005]维护数列 --- Splay

题目描述

请写一个程序,要求维护一个数列,支持以下 6 种操作:(请注意,格式栏 中的下划线‘ _ ’表示实际输入文件中的空格)
这里写图片描述

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

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

输入样例
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

输出样例
-1
10
1
10

说明
你可以认为在任何时刻,数列中至少有 1 个数。
输入数据一定是正确的,即指定位置的数在数列中一定存在。
50%的数据中,任何时刻数列中最多含有 30 000 个数;
100%的数据中,任何时刻数列中最多含有 500 000 个数。
100%的数据中,任何时刻数列中任何一个数字均在[-1 000, 1 000]内。
100%的数据中,M ≤20 000,插入的数字总数不超过 4 000 000 。

分析

  • 插入
    根据读入的数据构建一颗Splay(根节点记为rt)
    将pos提至root, pos + 1,提至root的右孩子,则只需要将rt插在root的右儿子的左儿子(此时必为空)处即可。
  • 删除
    处理出要删除的区间[l,r],然后常规操作(略)
  • 修改 & 翻转
    常规操作,找到区间。然后修改并打标记
    优先修改标记,修改后无需翻转。
    注意附加域的翻转(见下)
  • 求和
    略(好好维护就行)
  • 最大子序列
    由于是树形结构,因此考虑分治的方法
    令ls[l,r]为以l为起点的最大子序列,rs[l,r]为以r为终点的最大子序列,ms[l,r]为区间[l,r]的最大子序列
    转移方程【对于Splay而言】
    —ls[now] = max( ls[lch], sum[lch] + val[now] + ls[rch])
    —rs[now] = max(rs[rch], sum[rch] + val[now] + rs[lch])
    —ms[now] = max( max( ms[lch], ms[rch] ), rs[lch] + val[now] + ls[rch])
    对于区间翻转,除了左右子树交换之外,ls 与 rs 也应该交换
    对于特殊情况,若lch/rch不存在,则
    ls[lch/rch] = 0, rs[lch/rch] = 0, ms[lch/rch] = -INF
  • 注意
    为了避免边界问题,在首尾插入两个点
    注意内存,重复使用节点

代码

#include <cstdio>
#include <cstdlib>
#include <stack>
#include <algorithm>

#define IL inline
#define inf 0x3f3f3f3f

using namespace std;

IL int read()
{
    int k = 1, sum = 0;
    char c = getchar();
    for(; '0' > c || c > '9'; c = getchar())
    if(c == '-') k = -1;
    for(; '0' <= c && c <= '9'; c = getchar())
        sum = sum * 10 + c - '0';
    return sum * k;
}

struct node
{
    node *father;
    node *son[2];
    int size;
    int val;
    int sum;
    int ls, rs, ms; 
    bool upset, cov;

    IL node(int v = 0, node *f = 0)
    {
        father = f;
        son[0] = son[1] = 0;
        val = ms = sum = v;
        size = 1;
        ls = rs = (v > 0 ? v : 0);
        upset = cov = 0;
    }
};
node *root;
stack <node *> stk;
int n;
int num[500005];

IL int max_(int x, int y) { return x > y ? x : y;}

IL int ls(node *p) { return p ? p->ls : 0; }
IL int rs(node *p) { return p ? p->rs : 0; }
IL int ms(node *p) { return p ? p->ms : -inf; }
IL int sum(node *p) { return p ? p->sum : 0; }
IL int size(node *p) { return p ? p->size : 0; }
IL bool son(node *f, node *p) { return f ? (f->son[1] == p) : -1; }

IL void connect(node *f, node *p, bool k)
{
    if(!f) root = p; else  f->son[k] = p;
    if(p) p->father = f;
}

IL void updata(node *p)
{
    p->size = size(p->son[0]) + size(p->son[1]) + 1;
    p->sum = sum(p->son[0]) + sum(p->son[1]) + p->val;
    p->ms = max_( max_(ms(p->son[0]), ms(p->son[1])), p->val + rs(p->son[0]) + ls(p->son[1]));
    p->ls = max_(ls(p->son[0]), sum(p->son[0]) + p->val + ls(p->son[1]));
    p->rs = max_(rs(p->son[1]), sum(p->son[1]) + p->val + rs(p->son[0]));
}

IL void clean(node *p)
{
    if(p->cov)
    {
        p->cov = p->upset = 0;
        node *pp;
        for(int i = 0; i < 2; ++ i)
        if(p->son[i])
        {
            pp = p->son[i];
            pp->cov = 1;
            pp->val = p->val;
            pp->sum = pp->size * pp->val;
            pp->ls = pp->rs = max_(pp->sum, 0);
            pp->ms = ( pp->val > 0 ? pp->sum : pp->val );
        }
    }else
    if(p->upset)
    {
        p->upset = 0;
        node *pp;
        for(int i = 0; i < 2; ++ i)
        if(p->son[i])
        {
            pp = p->son[i];
            pp->upset ^= 1;
            swap(pp->ls, pp->rs);
            swap(pp->son[0], pp->son[1]);
        }
    }
} 

IL void rotate(node *p)
{
    node *f = p->father, *g = f->father;
    bool x = son(f, p), y = !x;

    connect(f, p->son[y], x);
    connect(g, p, son(g, f));
    connect(p, f, y);

    updata(f);
}

IL void splay(node *p, node *q)
{
    for(node *f, *g; p->father != q;)
    {
        f = p->father;
        g = f->father;

        if(g == q) rotate(p); else
        {
            if(son(g, f) ^ son(f, p))
                rotate(p), rotate(p);
            else
                rotate(f), rotate(p);
        }
    }
    updata(p);
}

IL node *findx(int t)
{
    for(node *p = root; t; )
    {
        clean(p);
        if(size(p->son[0]) >= t)
            p = p->son[0];
        else
        if(t - size(p->son[0]) == 1)
        {
            return p;
        }else
        {
            t -= size(p->son[0]) + 1;
            p = p->son[1];
        }
    }
}

IL node *newnode(int val, node *f)
{
    if(stk.empty())
    {
        return new node(val, f);
    }else
    {
        node *p = stk.top(); stk.pop();
        p->father = f;
        p->son[0] = p->son[1] = 0;
        p->ms = p->val = p->sum = val;
        p->size = 1;
        p->ls = p->rs = (val > 0 ? val : 0);
        p->upset = p->cov = 0;
        return p;
    }
}

IL void freenode(node *p)
{
    stk.push(p);
}

IL node *build(int l, int r, node *f)
{
    int mid = (l + r) >> 1;
    node *p = newnode(num[mid], f);
    if(l != mid) p->son[0] = build(l, mid - 1, p);
    if(r != mid) p->son[1] = build(mid + 1, r, p);
    updata(p);
    return p;
}

IL node *split(int l, int r)
{
    node *p = findx(l), *q = findx(r);
    splay(p, 0); splay(q ,p);
    return q;
}

IL void insert(int l)
{
    n = read();
    for(int i = 1; i <= n; ++ i) num[i] = read();
    node *rt = build(1, n, 0);
    node *p = split(l, l + 1);
    connect(p, rt, 0); 
    updata(p); updata(root);
}

IL void recyle(node *p)
{
    freenode(p);
    if(p->son[0]) recyle(p->son[0]);
    if(p->son[1]) recyle(p->son[1]);
}

IL void earse(int l)
{
    node *p = split(l - 1, l + read());
    recyle(p->son[0]);
    p->son[0] = 0;
    updata(p); updata(root);
}

IL void modify(int l)
{
    node *p = split(l -1, l + read())->son[0];
    p->cov = 1;
    p->val = read();
    p->sum = p->size * p->val;
    p->ls = p->rs = max_(p->sum, 0);
    p->ms = ( p->val > 0 ? p->sum : p->val );
    updata(p->father); updata(root);
}

IL void rever(int l)
{
    node *p = split(l - 1, l + read())->son[0];
    if(p->cov) return ;
    p->upset ^= 1;
    if(!p->upset) return ;
    swap(p->ls, p->rs);
    swap(p->son[0], p->son[1]);
    updata(p->father); updata(root);
}

IL int get_sum(int l)
{
    int r = l + read();
    if(l == r) return 0; 
    node *p = split(l - 1, r)->son[0];
    return p->sum;
}

IL int max_sum()
{
    node *p = split(1, size(root))->son[0];
    return p->ms;
}

int main()
{
    n = read() + 2;
    int m = read();
    for(int i = 2; i < n; ++ i) num[i] = read();
    num[1] = num[n] = -inf;
    root = build(1, n, 0);

    char c;
    for(int x, i = 1; i <= m; ++ i)
    {
        scanf(" %c",&c);
        if(c == 'I')
        {
            insert(read() + 1);
        }else
        if(c == 'D')
        {
            earse(read() + 1);
        }else
        if(c == 'R')
        {
            rever(read() + 1);
        }else
        if(c == 'G')
        {
            getchar(); getchar(); getchar();
            printf("%d\n", get_sum(read() + 1));
        }else
        if(c == 'M')
        {
            getchar();
            c = getchar();
            if(c == 'K')
            {
                getchar(); getchar();
                modify(read() + 1);
            }else
            if(c == 'X')
            {
                getchar(); getchar(); getchar(); getchar();
                printf("%d\n", max_sum());
            }
        }
    }
}

猜你喜欢

转载自blog.csdn.net/qq_27121257/article/details/79398220