• [NOI2005]维护数列——Splay


    题面

      洛谷P2042

    解析

        这道题集齐了大部分Splay的经典操作,上课时wys老师讲了一下,这个题还是很值得一做的

      基操:

        Splay上的所有区间操作都需要提取区间,如果要提取一个[l, r]的区间,只需要把l-1的点转到根,再把r+1的点转到根的右儿子,那么根的右儿子的左儿子的整颗子树就是我们要提取的区间

      操作1:插入

        这个题的插入并非插入一个数,而是插入一个数列,一个一个的插入肯定会T的,所以就把插入的数列先建成一棵树,再提取区间,这时根的右儿子的左儿子为空,只需要把新树的根挂在根的右儿子的左儿子上,最后更新信息即可

      操作2:删除

        还是先提取区间,断开根的右儿子与它的左儿子相连的边就行,但这道题的空间有限,需要回收节点编号,最好开个栈来存编号,用队列的话有点浪费空间,而且必须开很大的数组才能在CodeVS上AC,在洛谷上好像区别不大,当然我说的队列是手写队列,你用STL我也没话说

      操作3:修改

        同样是先提取区间,把根的右儿子的左儿子修改后打上标记即可

      操作4:翻转

        提取区间,把根的右儿子的左儿子修改后打上标记

      操作5:求和

        提取区间,输出

      操作6:求和最大的子序列的和

        终于不用提取区间了,直接输出就行。但维护信息的时候很麻烦,与线段树求和最大的子列类似,我们需要维护区间的子序列最大值,以及左右区间的最大子序列的和,在向上更新的时候,需要像下面这样操作, 其中ls是x的左儿子,rs是右儿子,mx是和最大子序列的和,lx是左区间最大子序列的和,rx是右区间最大子序列的和

      细节:

           0号节点的mx要赋负无穷,因为有些点没有左儿子或右儿子,避免更新答案时出错(大导演wys这个细节调了1个小时)

        标记下传的时候要注意有没有左儿子或右儿子,不然会改变0号节点的信息,我搞了半个小时

        伸展操作(splay)不要写挂了,我搞了1个小时

      代码:

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn = 500005, inf = 0x3f3f3f3f;
    
    template<class T> void read(T &re)
    {
        re=0;
        T sign=1;
        char tmp;
        while((tmp=getchar())&&(tmp<'0'||tmp>'9')) if(tmp=='-') sign=-1;
        re=tmp-'0';
        while((tmp=getchar())&&(tmp>='0'&&tmp<='9')) re=(re<<3)+(re<<1)+(tmp-'0');
        re*=sign;
    }
    
    int n, m, root, id[maxn], tot;
    int a[maxn];
    
    struct splay_tree{
        int s[2], siz, fa, tag;
        int val, mx, lx, rx, sum, c;
        void init(int x)
        {
            val = sum = mx = x;
            lx = rx = max(x, 0);
            siz = 1;
            c = inf;
        }
        void Clear()
        {
            s[0] = s[1] = siz = fa = tag = 0;
            val = lx = rx = sum = mx = 0;
            c = inf;
        }
    }tr[maxn];
    
    int stak[maxn], top;
    
    void update(int x)
    {
        int ls = tr[x].s[0], rs = tr[x].s[1];
        tr[x].sum = tr[ls].sum + tr[rs].sum + tr[x].val;
        tr[x].siz = tr[ls].siz + tr[rs].siz + 1;
        tr[x].mx = max(tr[ls].mx, tr[rs].mx);
        tr[x].mx = max(tr[x].mx, tr[ls].rx + tr[rs].lx + tr[x].val);
        tr[x].lx = max(tr[ls].lx, tr[ls].sum + tr[x].val + tr[rs].lx);
        tr[x].rx = max(tr[rs].rx, tr[rs].sum + tr[x].val + tr[ls].rx);
    }
    
    void spread(int x)
    {
        int ls = tr[x].s[0], rs = tr[x].s[1];
        if(tr[x].c != inf)
        {
            if(ls)
            {
                tr[ls].val = tr[ls].c = tr[x].c;
                tr[ls].sum = tr[ls].siz * tr[x].c;
                tr[ls].lx = tr[ls].rx = max(tr[ls].sum, 0);
                tr[ls].mx = max(tr[ls].val, tr[ls].sum);
            }
            if(rs)
            {
                tr[rs].val = tr[rs].c = tr[x].c;
                tr[rs].sum = tr[rs].siz * tr[x].c;
                tr[rs].lx = tr[rs].rx = max(tr[rs].sum, 0);
                tr[rs].mx = max(tr[rs].val, tr[rs].sum);
            }
            tr[x].c = inf;
            tr[x].tag = 0;
        }
        if(tr[x].tag)
        {
            if(ls)
            {
                tr[ls].tag ^= 1;
                swap(tr[ls].lx, tr[ls].rx);
                swap(tr[ls].s[0], tr[ls].s[1]);
            }
            if(rs)
            {
                tr[rs].tag ^= 1;
                swap(tr[rs].lx, tr[rs].rx);
                swap(tr[rs].s[0], tr[rs].s[1]);
            }
            tr[x].tag = 0;
        }
    }
    
    void Rotate(int x)
    {
        int y = tr[x].fa, z = tr[y].fa, k = (tr[y].s[1] == x), w = (tr[z].s[1] == y), son = tr[x].s[k^1];
        tr[y].s[k] = son;tr[son].fa = y;
        tr[x].s[k^1] = y;tr[y].fa = x;
        tr[z].s[w] = x;tr[x].fa = z;
        update(y);update(x);
    }
    
    void Splay(int x, int to)
    {
        while(tr[x].fa != to)
        {
            int y = tr[x].fa, z = tr[y].fa;
            if(z == to)
            {
                Rotate(x);
                break;
            }
            Rotate((tr[y].s[1] == x) != (tr[z].s[1] == y) ? x: y);
            Rotate(x);
        }
        if(!to)
            root = x;
    }
    
    int Find(int x)
    {
        int now = root;
        while(1)
        {
            spread(now);
            int ls = tr[now].s[0], rs = tr[now].s[1];
            if(x == tr[ls].siz + 1)     return now;
            if(x <= tr[ls].siz)     now = ls;
            else x -= tr[ls].siz + 1,  now = rs;
        }
    }
    
    void build(int l, int r,  int f)
    {
        int mid = (l + r)>>1, now = id[mid], pre = id[f];
        if(l == r)
            tr[now].init(a[mid]);
        if(l < mid)
            build(l, mid - 1, mid);
        if(mid < r)
            build(mid + 1, r, mid);
        tr[now].val = a[mid];
        tr[now].fa = pre;
        tr[now].c = inf;
        update(now);
        if(pre)
            tr[pre].s[mid >= f] = now;
    }
    
    void Insert(int pos, int len)
    {
        for( int i = 1; i <= len; ++i)
            read(a[i]);
        for( int i = 1; i <= len; ++i)
            if(top)
                id[i] = stak[top--];
            else
                id[i] = ++tot;
        build(1, len, 0);
        int x = id[(1+len)>>1];
        int y = Find(pos + 1), z = Find(pos + 2);
        Splay(y, 0);Splay(z, y);
        tr[x].fa = z;
        tr[z].s[0] = x;
        update(z);update(y);
    }
    
    void Recycle( int x)
    {
        if(!x)    return ;
        int ls = tr[x].s[0], rs = tr[x].s[1];
        stak[++top] = x;
        tr[x].Clear();
        if(ls)    Recycle(ls);
        if(rs)    Recycle(rs);
    }
    
    void Del(int pos, int len)
    {
        int x = Find(pos), y = Find(pos + len + 1);
        Splay(x, 0);Splay(y, x);
        Recycle(tr[y].s[0]);
        tr[y].s[0] = 0;
        update(y);update(x);
    }
    
    void Change(int pos, int len, int val)
    {
        int x = Find(pos), y = Find(pos + len + 1);
        Splay(x, 0);Splay(y, x);
        int z = tr[y].s[0];
        tr[z].val = tr[z].c = val;
        tr[z].sum = tr[z].siz * val;
        tr[z].lx = tr[z].rx = max(tr[z].sum, 0);
        tr[z].mx = max(tr[z].val, tr[z].sum);
        update(y);update(x);
    }
    
    void Rever(int pos, int len)
    {
        int x = Find(pos), y = Find(pos + len + 1);
        Splay(x, 0);Splay(y, x);
        int z = tr[y].s[0];
        if(tr[z].c == inf)
        {
            tr[z].tag ^= 1;
            swap(tr[z].lx, tr[z].rx);
            swap(tr[z].s[0], tr[z].s[1]);
            update(y);update(x);
        }
    }
    
    int Query(int pos, int len)
    {
        int x = Find(pos), y = Find(pos + len + 1);
        Splay(x, 0);Splay(y, x);
        int z = tr[y].s[0];
        return tr[z].sum;
    }
    
    int main()
    {
        read(n);read(m);
        tr[0].mx = a[1] = a[n+2] = -inf;
        for( int i = 1; i <= n; ++i)
            read(a[i+1]);
        for( int i = 1; i <= n + 2; ++i)
            id[i] = i;
        build(1, n + 2, 0);
        root = (n + 3)>>1;
        tot = n + 2;
        tr[0].s[1] = root;
        for( int i = 1; i <= m; ++i)
        {
            char opt[10];
            int pos, len;
            scanf("%s", opt);
            if(opt[0] == 'I')
            {
                read(pos);read(len);
                Insert(pos, len);
            }
            else if(opt[0] == 'D')
            {
                read(pos);read(len);
                Del(pos, len);
            }
            else if(opt[0] == 'M' && opt[2] == 'K')
            {
                int val;
                read(pos);read(len);read(val);
                Change(pos, len, val);
            }
            else if(opt[0] == 'R')
            {
                read(pos);read(len);
                Rever(pos, len);
            }
            else if(opt[0] == 'G')
            {
                read(pos);read(len);
                printf("%d
    ", Query(pos, len));
            }
            else
                printf("%d
    ", tr[root].mx);        
        }
        return 0;
    }
    View Code
  • 相关阅读:
    Ubuntu下一个openldapserver部署步骤
    秀球技:倒和其他无用
    POJ1201-Intervals(差动限制)
    Scrapy研究和探索(七)——如何防止被ban大集合策略
    word 一些有用的技巧
    Java设计模式偷跑系列(十二)组合模式建模和实现
    Sql使用视图(简单的视图)适合入门-level
    cocos2d 缓存池 对象的再利用
    txt 开关 csv 可通用 工具
    使用SharePoint创建和定义自己的网站页面
  • 原文地址:https://www.cnblogs.com/Joker-Yza/p/11224430.html
Copyright © 2020-2023  润新知