[SHOI 2015] 脑洞治疗仪

Posted evenbao

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[SHOI 2015] 脑洞治疗仪相关的知识,希望对你有一定的参考价值。

[题目链接]

          https://www.lydsy.com/JudgeOnline/problem.php?id=4592

[算法]

       对于操作1 , 我们首先查询区间[l0 , r0]中有多少个1 , 然后二分求出最大的x(x <= r1)使得[l1 , x]中0的个数 <= [l0 , r0]中1的个数

       对于操作2 , 对于一段区间[l , r] , 我们将它分成[l , mid]和[mid + 1 , r]两个子区间 , 那么 , 最长连续的0的个数有三种情况 :

       1. 在[l , mid]中 2. 在[mid + 1 , r]中 3. mid向前延伸最多的0的个数 + (mid + 1)向后延伸最多的0的个数

       线段树维护即可

       时间复杂度 : O(NlogN ^ 2)

[代码]

        

#include<bits/stdc++.h>
using namespace std;
#define MAXN 200010
typedef long long ll;
typedef long double ld;
const int inf = 1e9;

int n , m;

template <typename T> inline void chkmax(T &x , T y) { x = max(x , y); }
template <typename T> inline void chkmin(T &x , T y) { x = min(x , y); }
template <typename T> inline void read(T &x)
{
    T f = 1; x  = 0;
    char c = getchar();
    for (; !isdigit(c); c = getchar()) if (c == -) f = -f;
    for (; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + c - 0;
    x *= f;
}

struct Segment_Tree
{
    struct Node
    {
        int l , r;
        int lm0 , rm0 , value , cnt;
        int tag;    
    } a[MAXN << 2];
    inline void build(int index , int l , int r)
    {
        a[index].l = l , a[index].r = r;
        a[index].cnt = r - l + 1;
        a[index].tag = -1;
        if (l == r) return;
        int mid = (l + r) >> 1;
        build(index << 1 , l , mid);
        build(index << 1 | 1 , mid + 1 , r);
    }
    inline void update(int x)
    {
        int l = a[x].l , r = a[x].r;
        int mid = (l + r) >> 1;
        a[x].cnt = a[x << 1].cnt + a[x << 1 | 1].cnt;
        if (a[x << 1].lm0 == mid - l + 1) a[x].lm0 = mid - l + 1 + a[x << 1 | 1].lm0;
        else a[x].lm0 = a[x << 1].lm0;
        if (a[x << 1 | 1].rm0 == r - mid) a[x].rm0 = r - mid + a[x << 1].rm0;
        else a[x].rm0 = a[x << 1 | 1].rm0;
        a[x].value = max(a[x << 1].value , a[x << 1 | 1].value);
        chkmax(a[x].value , a[x << 1].rm0 + a[x << 1 | 1].lm0);
    }
    inline void pushdown(int index)
    {
        int l = a[index].l , r = a[index].r;
        int mid = (l + r) >> 1;
        if (l == r) return;
        if (a[index].tag == 0)
        {
            a[index << 1].cnt = a[index << 1 | 1].cnt = 0;
            a[index << 1].value = mid - l + 1;
            a[index << 1 | 1].value = r - mid;
            a[index << 1].lm0 = a[index << 1].rm0 = mid - l + 1;
            a[index << 1 | 1].lm0 = a[index << 1 | 1].rm0 = r - mid;
            a[index << 1].tag = a[index << 1 | 1].tag = a[index].tag;
            a[index].tag = -1;
        }
        if (a[index].tag == 1)
        {
            a[index << 1].cnt = mid - l + 1;
            a[index << 1 | 1].cnt = r - mid;
            a[index << 1].value = a[index << 1 | 1].value = 0;
            a[index << 1].lm0 = a[index << 1].rm0 = 0;
            a[index << 1 | 1].lm0 = a[index << 1 | 1].rm0 = 0;
            a[index << 1].tag = a[index << 1 | 1].tag = a[index].tag;
            a[index].tag = -1;
        }
    }
    inline void modify(int index , int l , int r)
    {
        if (a[index].l == l && a[index].r == r)
        {
            a[index].cnt = 0;
            a[index].lm0 = a[index].rm0 = r - l + 1;
            a[index].value = r - l + 1;
            a[index].tag = 0;
            return;
        }
        pushdown(index);
        int mid = (a[index].l + a[index].r) >> 1;
        if (mid >= r) modify(index << 1 , l , r);
        else if (mid + 1 <= l) modify(index << 1 | 1 , l , r);
        else
        {
            modify(index << 1 , l , mid);
            modify(index << 1 | 1 , mid + 1 , r);
        }
        update(index);
    }
    inline int queryA(int index , int l , int r)
    {
            if (a[index].l == l && a[index].r == r)
                    return a[index].cnt;
            pushdown(index);
            int mid = (a[index].l + a[index].r) >> 1;
            if (mid >= r) return queryA(index << 1 , l , r);
            else if (mid + 1 <= l) return queryA(index << 1 | 1 , l , r);
            else return queryA(index << 1 , l , mid) + queryA(index << 1 | 1 , mid + 1 , r);
        }
        inline int queryB(int index , int l , int r)
    {
        if (a[index].l == l && a[index].r == r)
            return a[index].value;
        pushdown(index);
        int mid = (a[index].l + a[index].r) >> 1;
        if (mid >= r) return queryB(index << 1 , l , r);
        else if (mid + 1 <= l) return queryB(index << 1 | 1 , l , r);
        {
                      int ret = max(queryB(index << 1 , l , mid) , queryB(index << 1 | 1 , mid + 1 , r));
            chkmax(ret , min(mid - l + 1 , a[index << 1].rm0) + min(r - mid , a[index << 1 | 1].lm0));
            return ret;
        }
    }
    inline void change(int index , int l , int r)
    {
            if (l > r) return;
                 if (a[index].l == l && a[index].r == r)
                 {
                         a[index].cnt = r - l + 1;
                        a[index].lm0 = a[index].rm0 = a[index].value = 0;
                        a[index].tag = 1;
                        return;        
                }
                pushdown(index);
                int mid = (a[index].l + a[index].r) >> 1;
                if (mid >= r) change(index << 1 , l , r);
                else if (mid + 1 <= l) change(index << 1 | 1 , l , r);
                else
                {
                        change(index << 1 , l , mid);
                        change(index << 1 | 1 , mid + 1 , r);
                }
                update(index);
    }
} SGT;

int main()
{
           
    read(n); read(m);
    SGT.build(1 , 1 , n);
    for (int i = 1; i <= m; i++)
    {
        int type;
        read(type);
        if (type == 0)
        {
            int x , y;
            read(x); read(y);
            SGT.modify(1 , x , y);
        } else if (type == 1)
        {
            int l0 , r0 , l1 , r1;
            read(l0); read(r0); read(l1); read(r1);
            int cnt = SGT.queryA(1 , l0 , r0);
            SGT.modify(1 , l0 , r0);
            int l = l1 , r = r1 , loc = 0;
            while (l <= r)
            {
                    int mid = (l + r) >> 1;
                    if ((mid - l1 + 1) - SGT.queryA(1 , l1 , mid) <= cnt)
                    {
                            loc = mid;
                            l = mid + 1;
                                } else r = mid - 1;
                        }
            SGT.change(1 , l1 , loc);
        } else
        {
            int l , r;
            read(l); read(r);
            printf("%d
" , SGT.queryB(1 , l , r));
        }
    }
    
    return 0;
}

 

以上是关于[SHOI 2015] 脑洞治疗仪的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ4592[Shoi2015]脑洞治疗仪 线段树

LOJ #2037. 「SHOI2015」脑洞治疗仪

[SHOI2015]脑洞治疗仪

[SHOI2015]脑洞治疗仪(恶心的线段树,区间最大子段和)

SHOI2015脑洞治疗仪(恶心的线段树,区间最大子段和)

[SHOI 2015] 脑洞治疗仪