• [BZOJ 1500] [NOI2005] 维修数列


    题目链接:BZOJ - 1500

    题目分析

    我要先说一下,这道题我写了一晚上,然后Debug了一整个白天..........再一次被自己的蒟蒻程度震惊= =

    这道题是传说中的Splay维护数列的Boss题目。

    前面的几个操作和询问看起来比较正常,就是最后一个维护最大区间和比较复杂。

    其实这个也并不是十分复杂,只是要多维护一点东西,事实证明,我代码里的错误都不是与这个询问有关的。

    维护每个节点的 Lmx[x] ,即这个节点的子树代表的区间的从左端开始的最大权值和。Rmx[x],同理。Mx[x],这个区间的最大权值和。

    然而我的最大权值和都是可以为空的,也就是说如果只能取负数我就什么都不取,就是0。

    题目规定的最大权值区间是不能为空的,所以我多维护了一个 Max[x],询问的时候判断如果 Max[x] < 0 ,就输出 Max[x],否则输出我维护的 Mx[x]。

    ............................然后就是我Debug了一天的东西.........................

    经过一天悲剧的探索与尝试,我发现我的错误是出现在了Reverse操作有关的东西。

    PushDown写得有非常严重的错误,下面来梳理一下正确的写法,以后要固定一下写法,不能一个代码一个写法...

    首先,翻转一个区间的时候,假如这个区间子树的根节点是 x,就Reverse(x)。

    之后,PushDown(x) 的时候,判断 Rev[x] 是否为 1,如果是1,就Reverse(Son[x][0]); Reverse(Son[x][1]);

    注意,交换左右儿子的操作在Reverse(x)里完成。Rev[x]为1表示的是x的两个儿子还应被 Reverse,但是x的两个儿子的顺序已经是对的。是x的孙子的顺序需要被交换。

    代码:

    void Reverse(int x)
    {
        Rev[x] ^= 1;
        swap(Son[x][0], Son[x][1]);    
    }        
    
    void PushDown(int x)
    {
        if (Rev[x] == 0) return;
        if (Son[x][0]) Reverse(Son[x][0]);   
        if (Son[x][1]) Reverse(Son[x][1]);       
      Rev[x] = 0;
    }
    

      

    代码

    #include <iostream>
    #include <cstdlib>
    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
     
    using namespace std;
     
    const int MaxN = 1000000 + 5, INF = 999999999;
     
    inline void Read(int &Num) 
    {
        char c = getchar();
        bool Neg = false;
        while (c < '0' || c > '9')
        {
            if (c == '-') Neg = true;
            c = getchar();
        }
        Num = c - '0'; c = getchar();
        while (c >= '0' && c <= '9')
        {
            Num = Num * 10 + c - '0';
            c = getchar();
        }
        if (Neg) Num = -Num;
    }
     
    int n, m, Root, Index, Tot1, Tot2, Len;
    int V[MaxN], A[MaxN], Father[MaxN], Son[MaxN][2], Sum[MaxN], Rev[MaxN], Stack[MaxN];
    int Max[MaxN], Size[MaxN], Lmx[MaxN], Rmx[MaxN], Mx[MaxN], D[MaxN];
     
    bool Rep[MaxN];
     
    char Str[15];
     
    inline int gmax(int a, int b) {return a > b ? a : b;}
    inline int gmin(int a, int b) {return a < b ? a : b;}
     
    inline void Update(int x) 
    {
        Size[x] = Size[Son[x][0]] + Size[Son[x][1]] + 1;
        Sum[x] = Sum[Son[x][0]] + Sum[Son[x][1]] + A[x];
        Max[x] = gmax(A[x], gmax(Max[Son[x][0]], Max[Son[x][1]]));
        Lmx[x] = gmax(Lmx[Son[x][0]], Sum[Son[x][0]] + A[x] + Lmx[Son[x][1]]);
        Rmx[x] = gmax(Rmx[Son[x][1]], Sum[Son[x][1]] + A[x] + Rmx[Son[x][0]]);
        Mx[x] = gmax(Rmx[Son[x][0]] + A[x] + Lmx[Son[x][1]], gmax(Rmx[x], Lmx[x]));
        Mx[x] = gmax(Mx[x], gmax(Mx[Son[x][0]], Mx[Son[x][1]]));
    }
     
    inline void Replace(int x, int Num) 
    {
        Rep[x] = true;
        D[x] = Num;
        A[x] = Num;
        Sum[x] = Num * Size[x];
        Max[x] = Num; 
        Lmx[x] = Rmx[x] = Mx[x] = gmax(0, Sum[x]);
    }
     
    inline void Reverse(int x) 
    {
    	Rev[x] ^= 1;
    	swap(Son[x][0], Son[x][1]);
    	swap(Lmx[x], Rmx[x]);
    }
    
    inline void PushDown(int x) 
    {
        if (Rep[x])
        {
            if (Son[x][0]) Replace(Son[x][0], D[x]);
            if (Son[x][1]) Replace(Son[x][1], D[x]);
            Rep[x] = false;
        }
        if (Rev[x]) 
        {
            if (Son[x][0]) Reverse(Son[x][0]);
            if (Son[x][1]) Reverse(Son[x][1]);
            Rev[x] = 0;
        }
    }
     
    int NewNode(int a) 
    {
        int x;
        if (Tot2 > 0) x = Stack[Tot2--];
        else x = ++Tot1;
        Size[x] = 1;
        Son[x][0] = Son[x][1] = 0;
        Father[x] = 0;
        A[x] = Sum[x] = Max[x] = a;
        Lmx[x] = Rmx[x] = Mx[x] = gmax(a, 0);
        Rev[x] = 0; Rep[x] = false;
        return x;
    }
     
    int Build(int s, int t)
    {
        int x, m = (s + t) >> 1;
        x = NewNode(V[m]);
        if (s < m) 
        {
            Son[x][0] = Build(s, m - 1);
            Father[Son[x][0]] = x;
        }
        if (t > m) 
        {
            Son[x][1] = Build(m + 1, t);
            Father[Son[x][1]] = x;
        }
        Update(x);
        return x;
    }
     
    void Rotate(int x, int f) 
    {
        int y = Father[x];
        if (y == 0) return;
        Son[y][f ^ 1] = Son[x][f];
        if (Son[x][f]) Father[Son[x][f]] = y;
        Father[x] = Father[y];
        if (Father[y]) 
        {
            if (y == Son[Father[y]][0]) Son[Father[y]][0] = x;
            else Son[Father[y]][1] = x;
        }
        Son[x][f] = y;
        Father[y] = x;
        Update(y);
        Update(x);
    }
     
    void Splay(int x, int d) 
    {
        if (x == d) return;
        int y;
        while (Father[x] != d) 
        {
            y = Father[x];
            if (Father[y] == d) 
            {
                if (x == Son[y][0]) Rotate(x, 1);
                else Rotate(x, 0);
                break;          
            }
            if (y == Son[Father[y]][0]) 
            {
                if (x == Son[y][0])
                {
                    Rotate(y, 1);
                    Rotate(x, 1);
                }
                else
                {
                    Rotate(x, 0);
                    Rotate(x, 1);
                }
            }
            else
            {
                if (x == Son[y][1])
                {
                    Rotate(y, 0);
                    Rotate(x, 0);
                }
                else
                {
                    Rotate(x, 1);
                    Rotate(x, 0);
                }
            }
        }
        if (Father[x] == 0) Root = x;
    }
     
    int Find(int Num) 
    {
        int x = Root, k = Num;
        PushDown(x);
        while (Size[Son[x][0]] + 1 != k)
        {
            if (Size[Son[x][0]] + 1 > k)
            {
                x = Son[x][0];
            }
            else
            {
                k -= Size[Son[x][0]] + 1;
                x = Son[x][1];
            }
            PushDown(x);
        }
        return x;
    }
     
    void Delete(int x) 
    {
        if (x == 0) return;
        if (Son[x][0]) Delete(Son[x][0]);
        if (Son[x][1]) Delete(Son[x][1]);
        Stack[++Tot2] = x;
    }
    
    int main() 
    {
        scanf("%d%d", &n, &m);
        Tot1 = Tot2 = 0;
        Len = n;
        for (int i = 1; i <= n; ++i) Read(V[i]);
        Max[0] = -INF;
        int Temp;
        Root = Build(1, n);
        Splay(Find(1), 0);
        Temp = NewNode(-INF);
        Son[Root][0] = Temp;
        Father[Temp] = Root;
        Update(Root);
        Splay(Find(n + 1), 0);
        Temp = NewNode(-INF);
        Son[Root][1] = Temp;
        Father[Temp] = Root;
        Update(Root);
        int Pos, Tot, New, Num, x, y;
        for (int i = 1; i <= m; ++i) 
        {
            scanf("%s", Str);
            if (strcmp(Str, "INSERT") == 0) 
            {
                Read(Pos); Read(Tot);
                Len += Tot;
                for (int j = 1; j <= Tot; ++j) scanf("%d", &V[j]);
                New = Build(1, Tot);
                x = Find(Pos + 1);
                y = Find(Pos + 2);
                Splay(x, 0);
                Splay(y, x);
                Son[y][0] = New;
                Father[New] = y;
                Update(y);
                Update(x);
            }
            else if (strcmp(Str, "DELETE") == 0)
            {
                Read(Pos); Read(Tot);
                Len -= Tot;
                x = Find(Pos);
                y = Find(Pos + Tot + 1);
                Splay(x, 0);
                Splay(y, x);
                Delete(Son[y][0]);
                Son[y][0] = 0;
                Update(y);
                Update(x);
            }
            else if (strcmp(Str, "MAKE-SAME") == 0)
            {
                Read(Pos); Read(Tot); Read(Num);
                x = Find(Pos);
                y = Find(Pos + Tot + 1);
                Splay(x, 0);
                Splay(y, x);
                Replace(Son[y][0], Num);
                Update(y);
                Update(x);
            }
            else if (strcmp(Str, "REVERSE") == 0)
            {
                Read(Pos); Read(Tot);
                x = Find(Pos);
                y = Find(Pos + Tot + 1);
                Splay(x, 0);
                Splay(y, x);
                Reverse(Son[y][0]);
                Update(y);
                Update(x);
            }
            else if (strcmp(Str, "GET-SUM") == 0)
            {
                Read(Pos); Read(Tot);
                x = Find(Pos);
                y = Find(Pos + Tot + 1);
                Splay(x, 0);
                Splay(y, x);
                printf("%d
    ", Sum[Son[y][0]]);
            }
            else if (strcmp(Str, "MAX-SUM") == 0)
            {
            	x = Find(1);
            	y = Find(Len + 2);
            	Splay(x, 0);
            	Splay(y, x);
            	if (Max[Son[y][0]] <= 0) printf("%d
    ", Max[Son[y][0]]);
                else printf("%d
    ", Mx[Son[y][0]]);
            }
        }
        return 0;
    }
    

      

  • 相关阅读:
    MongoDB 基础命令 (MongoDB Shell)
    MongoDB 在 Mac OSX 平台安装
    数组根据index拆分和查询下标
    简单介绍递归算法以及应用场景
    android studio ndk开发环境搭建
    基于vue开发的多功能的时间选择器组件,开箱即用
    简单了解JS中的几种遍历
    零基础学习webpack打包管理
    让你高效的理解JavaScript中的同步、异步和事件循环
    学习flex布局(弹性布局)
  • 原文地址:https://www.cnblogs.com/JoeFan/p/4336035.html
Copyright © 2020-2023  润新知