BZOJ 1251 绳命中第一道SPLAY

不要问蒟蒻标题是怎么回事。蒟蒻就是蒟蒻,T^T到现在才会写SPLAY。

感觉这道题的SPLAY也没啥好讲的,很基础。第一次写SPLAY,不过思路还是比较明朗。只不过最开始写这道题的时候傻乎乎的只给“加”的操作打标记,没给“翻转”打标记,T了一次。再加上自己这凌乱的代码、数不清的细节错误,调了老长时间。

有这么一些值得我注意的细节:

  1. find()过程中要pushdown
  2. rotate()前要分别pushdown父节点和当前节点,之后要分别maintain父节点和当前节点
  3. rotate()过程中别忘了P[fa].fa的一个字节点指针要改变
  4. 合并和分裂操作过程中也要pushdown和maintain
  5. 注意P[0]的值不要影响有效的节点的值的计算
#include <cstdio>
#include <cstring>
#include <algorithm>
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 put (int x)
{
    if (x < 0) {putchar ('-'); x = -x;}
    if (x == 0) {putchar ('0');}
    char s[15]; int num = 0;
    while (x) s[++num] = (x%10)+48, x /= 10;
    while (num) putchar (s[num--]);
    putchar ('\n');
}

struct node 
{
    int k, lc, rc, fa, sz, ad, re, mx;
    void reset() {k=lc=rc=fa=sz=ad=re=0; mx=-(1<<30);}
};

struct SplayTree
{
    node P[50005]; int cnt, root;

    void build (int rt, int sz)
    {
        P[rt].sz = sz; int half = sz>>1;
        if (half) {P[++cnt].fa=rt, P[rt].lc=cnt; build(cnt,half);}
        half = sz - half - 1;
        if (half) {P[++cnt].fa=rt, P[rt].rc=cnt; build(cnt,half);}
    }
    void initialize (int sz) {build(cnt=root=1, sz);}

    void pushdown (int rt)
    {
        if (P[rt].ad)
        {
            int ad = P[rt].ad, lc = P[rt].lc, rc = P[rt].rc;
            P[lc].k += ad, P[lc].ad += ad, P[lc].mx += ad;
            P[rc].k += ad, P[rc].ad += ad, P[rc].mx += ad;
            P[rt].ad = 0;
        }
        if (P[rt].re)
        {
            int lc = P[rt].lc, rc = P[rt].rc;
            swap(P[lc].lc, P[lc].rc);
            swap(P[rc].lc, P[rc].rc);
            P[lc].re ^= 1, P[rc].re ^= 1;
            P[rt].re = 0;
        }
    }

    void maintain (int rt)
    {
        P[0].reset();
        int lc = P[rt].lc, rc = P[rt].rc;
        P[rt].sz = P[lc].sz + P[rc].sz + 1;
        P[rt].mx = max (max(P[lc].mx,P[rc].mx), P[rt].k);
    }

    int find (int rt, int k)
    {
        int rk = P[P[rt].lc].sz+1;
        if (rk == k) return rt;
        pushdown(rt);
        if (rk > k) return find (P[rt].lc, k);
        if (rk < k) return find (P[rt].rc, k-rk);
    }

    void rotate (int rt)
    {
        int fa = P[rt].fa, gfa = P[fa].fa;
        pushdown(fa); pushdown(rt);
        if (P[fa].lc == rt)
        {
            P[fa].lc = P[rt].rc, P[P[rt].rc].fa = fa;
            P[rt].rc = fa, P[fa].fa = rt;
        }
        else
        {
            P[fa].rc = P[rt].lc, P[P[rt].lc].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;
        if (fa == root) root = rt, P[rt].fa = 0;
        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);
        }
    }

    void merge (int L, int R)
    {
        if (!L) {root=R; return;}
        if (!R) {root=L; return;}
        root = L;
        splay (find(L,P[L].sz));
        pushdown (root);
        P[root].rc = R, P[R].fa = root;
        maintain (root);
    }

    int split (int k, bool po)
    {
        int rt = find (root, k), t;
        splay (rt); pushdown (rt);
        if (po) t=P[rt].lc, P[rt].lc=0;
        else t=P[rt].rc, P[rt].rc=0;
        P[t].fa = 0; maintain(rt);
        return t;
    }

    void add (int L, int R, int V)
    {
        int op = split(L,1), op2 = split(R-L+1,0);
        P[root].k+=V, P[root].mx+=V, P[root].ad+=V;
        merge (root,op2);
        merge (op, root);
    }

    void rever (int L, int R)
    {
        int op = split(L,1), op2 = split(R-L+1,0);
        swap(P[root].lc, P[root].rc);
        P[root].re ^= 1;
        merge (root,op2);
        merge (op, root);
    }

    void getmax (int L, int R)
    {
        int op = split(L,1), op2 = split(R-L+1,0);
        put (P[root].mx);
        merge (root,op2);
        merge (op, root);
    }
}Solve;

int n, m;

int main ()
{
    get (n); get (m);
    Solve.initialize(n);
    while (m--)
    {
        int cmd, L, R, V; get (cmd); get (L); get (R);
        if (cmd == 1) {get (V); Solve.add(L,R,V);}
        if (cmd == 2) Solve.rever(L,R); 
        if (cmd == 3) Solve.getmax(L,R);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值