NOI 2005 BZOJ 1500 维护数列

这道算是一道合格的Splay基础题。距离上一次那道简单的Splay时间比较长,因为经历了元旦晚会和之后的一个小假期没写题。
这道题涵盖的Splay的操作还是比较多的,适合练手。写的时候思路一定要清晰,否则不好调。
推荐自顶向下写。我就是先写的最大的框架,判断输入,调用哪个函数。写出大框架之后就轮到挨个写函数了,这些函数也是有上下关系的,最靠上的当然就是最直接的对应每个操作的函数。我使用分裂和合并操作来完成它们。这样很简单地写完了这些函数。之后就该写其下一层的分裂和合并,其中涉及到splay,pushdown和maintain,思路清晰,很快写好。之后写下一层的splay,这个函数写得很简短,就用到了rotate。再最后,就应该写最底层的pushdown,maintain,rotate和find。一气呵成,写完代码大概用了1个小时多一点。
然而,调试的过程有一点坎坷(被COGS坑了一下,本地怎么跑都没事,COGS上就是全T,完全没有输出,加了内存池优化空间后在BZOJ上是过了)。细节较多的是mx的维护,在maintain中需要注意一下。还有就是maintain的调用的时间,以及调用时要保证合法性(比如偷懒的我在maintain里没有判断lc和rc是否为0就直接拿它们更新rt,那么就要保证lc或rc是0的时候的su,ml,mr,mx不会影响到rt)。

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

void get (int &x)
{
    char c = getchar(); bool neg = 0; x = 0; 
    while (c < '0' || c > '9') {if (c == '-') neg = 1; c = getchar();}
    while (c <= '9' && c >= '0') x = x*10+c-48, c = getchar();
    if (neg) x = -x;
}
void get (char *s)
{
    char c = getchar(); int num = 0;
    while (c < 'A' || c > 'Z') c = getchar();
    while ((c <= 'Z' && c >= 'A') || c == '-') s[num++] = c, c = getchar();
}
void put (int x)
{
    if (x == 0) putchar('0');
    if (x < 0) {putchar('-'); x = -x;}
    char s[15]; int num = 0;
    while (x) s[++num] = (x%10)+48, x /= 10;
    while (num) putchar(s[num--]);
    putchar ('\n');
}
int max (int a, int b, int c, int d, int e)
{
    return max(a,max(b,max(c,max(d,e))));
}

queue <int> mem;

struct node 
{
    int va, lc, rc, fa, sz, ch, re, su, ml, mr, mx;
    void set0()
    {va=lc=rc=fa=sz=re=su=0, ch=ml=mr=mx=-(1<<20);}
};

struct SplayTree
{
    node P[500005]; int root;

    //flags : ch re
    void pushdown (int rt)
    {
        int lc = P[rt].lc, rc = P[rt].rc;
        if (P[rt].ch >= -1000)
        {
            int ch = P[rt].ch;
            P[lc].ch = P[lc].va = ch;
            P[rc].ch = P[rc].va = ch;
            P[lc].su = ch*P[lc].sz;
            P[rc].su = ch*P[rc].sz;
            if (ch <= 0) 
                P[lc].ml = P[lc].mr = P[lc].mx = ch,
                P[rc].ml = P[rc].mr = P[rc].mx = ch;
            else P[lc].ml = P[lc].mr = P[lc].mx = P[lc].su;
                 P[rc].ml = P[rc].mr = P[rc].mx = P[rc].su;
            P[rt].ch = -(1<<20);
        }
        if (P[rt].re)
        {
            P[lc].re ^= 1, P[rc].re ^= 1;
            swap (P[lc].lc, P[lc].rc);
            swap (P[lc].ml, P[lc].mr);
            swap (P[rc].lc, P[rc].rc);
            swap (P[rc].ml, P[rc].mr);
            P[rt].re = 0;
        }
    }
    //int va, lc, rc, fa, sz, ch, re, su, ml, mr, mx;
    void maintain (int rt)
    {
        P[0].set0();
        int lc = P[rt].lc, rc = P[rt].rc;
        P[rt].sz = P[lc].sz + P[rc].sz + 1;
        P[rt].su = P[lc].su + P[rc].su + P[rt].va;
        P[rt].ml = max (P[lc].ml, P[lc].su+P[rt].va+max(P[rc].ml,0));
        P[rt].mr = max (P[rc].mr, P[rc].su+P[rt].va+max(P[lc].mr,0));
        P[rt].mx = max (P[rt].ml,P[rt].mr,max(P[lc].mr,0)+P[rt].va+max(P[rc].ml,0),P[lc].mx,P[rc].mx);
    }
    int makenewtree (int tot)
    {
        if (!tot) return 0;
        int rt = mem.front(), lc, rc, lcsz=tot/2, rcsz=tot-lcsz-1;
        mem.pop();
        P[rt].sz = tot; P[rt].ch = -(1<<30);
        P[rt].lc = makenewtree(lcsz);
        P[P[rt].lc].fa = rt;
        get(P[rt].va);
        P[rt].rc = makenewtree(rcsz);
        P[P[rt].rc].fa = rt;
        maintain(rt);
        return rt;
    }
    int find (int rt, int k)
    {
        if (!rt || !k) return 0;
        int rk = P[P[rt].lc].sz+1;
        pushdown (rt);
        if (rk == k) return rt;
        if (rk >  k) return find (P[rt].lc, k);
        if (rk <  k) return find (P[rt].rc, k-rk);
    }
    void reuse (int rt)
    {
        if (!rt) return ;
        mem.push (rt);
        reuse (P[rt].lc);
        reuse (P[rt].rc);
        P[rt].set0();
    }
    void rotate (int rt)
    {
        int fa = P[rt].fa, gfa = P[fa].fa;
        if (fa == root) root = rt;
        pushdown(fa); pushdown(rt);
        if (P[fa].lc == rt)
        {
            P[fa].lc = P[rt].rc, P[P[fa].lc].fa = fa;
            P[rt].rc = fa, P[fa].fa = rt;
        }
        else
        {
            P[fa].rc = P[rt].lc, P[P[fa].rc].fa = fa;
            P[rt].lc = fa, P[fa].fa = rt;
        }
        if(P[gfa].lc == fa) P[gfa].lc=rt; else P[gfa].rc=rt;
        P[rt].fa = gfa;
        maintain(fa); maintain(rt);
    }
    void splay (int rt)
    {
        while (rt != root)
        {
            int fa = P[rt].fa, gfa = P[fa].fa;
            if (gfa && (P[fa].lc==rt)==(P[gfa].lc==fa)) rotate(fa);
            rotate(rt);
        }
    }
    int split (int rt, int op) // 1 left 0 right
    {
        if (!rt) return 0;
        int t;
        splay (rt);
        pushdown(root);
        if(op) t=P[rt].lc, P[rt].lc=P[t].fa=0; 
        else   t=P[rt].rc, P[rt].rc=P[t].fa=0;
        maintain(root);  
        return t;
    }
    void merge (int L, int R)
    {
        if (!L) {root=R; return;}
        if (!R) {root=L; return;}
        root = L;
        splay (find(root,P[root].sz));
        pushdown(root);
        P[root].rc = R, P[R].fa = root;
        maintain(root);
    }

    void insert (int pos, int tot)
    {
        int rt = makenewtree(tot);
        if (!pos) merge (rt, root);
        else
        {
            int op = split (find(root,pos),0);
            merge (root, rt);
            merge (root, op);
        }
    }
    void erase (int pos, int tot)
    {
        int op = split (find(root,pos),1);
        if (tot+1 <= P[root].sz) 
        {
            reuse(split (find(root,tot+1), 1));
            merge (op, root);
        }
        else
        {
            reuse (root);
            root = op;
        }
    }
    void update (int pos, int tot)
    {
        int c; get(c);
        int op = split (find(root,pos),1);
        int op2= split (find(root,tot),0);
        P[root].ch = P[root].va = c, P[root].su = c*P[root].sz;
        if (c <= 0) P[root].ml = P[root].mr = P[root].mx = c;
        else P[root].ml = P[root].mr = P[root].mx = P[root].su;
        merge (root,op2);
        merge (op, root);
    }
    void rever (int pos, int tot)
    {
        int op = split (find(root,pos),1);
        int op2= split (find(root,tot),0);
        P[root].re ^= 1; 
        swap(P[root].ml, P[root].mr);
        swap(P[root].lc, P[root].rc);
        merge (root,op2);
        merge (op, root);
    }
    void getsum (int pos, int tot)
    {
        if (!tot) {puts("0"); return ;}
        int op = split (find(root,pos),1);
        int op2= split (find(root,tot),0);
        put (P[root].su); 
        merge (root,op2);
        merge (op, root);
    }
    void maxsum (int pos, int tot)
    {
        put (P[root].mx); 
    }
}Solve;

int n, m;

int getcommand()
{
    char s[15]; get(s);
    if (s[0] == 'I') return 1;
    if (s[0] == 'D') return 2;
    if (s[0] == 'R') return 4;
    if (s[0] == 'G') return 5;
    if (s[0] == 'M' && s[2] == 'K') return 3;
    return 0;
}

int main()
{
    get(n); get(m);
    //insert(a,b) insert b numbers behind a
    for (int i = 1; i <= 500000; i++) mem.push(i);
    Solve.insert(0, n);
    while (m--)
    {
        int cmd = getcommand(), pos, tot;
        if (cmd) {get(pos); get(tot);}
        if (cmd == 1) Solve.insert(pos, tot); 
        if (cmd == 2) Solve.erase (pos, tot);
        if (cmd == 3) Solve.update(pos, tot);
        if (cmd == 4) Solve.rever (pos, tot);
        if (cmd == 5) Solve.getsum(pos, tot);
        if (cmd == 0) Solve.maxsum(pos, tot);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值