BZOJ 1858【线段树】

 题意:
 0 a b 把 [a, b] 区间内的所有数全变成0
 1 a b 把 [a, b] 区间内的所有数全变成1
 2 a b 把 [a,b] 区间内的所有数全部取反
 3 a b 询问 [a, b] 区间内总共有多少个1
 4 a b 询问 [a, b] 区间内最多有多少个连续的1
 思路:
首先 线段树 可以搞个标记 flag 是否都是 1(flag=1)/0(flag=-1) LAZY一下
询问区间有多少个 1 ,那就是求和而已?
询问区间最多有多少个连续的1 ?
主要是区间合并的时候要判断
左儿子的Right_Num ==1 && 右儿子的Left_Num ==1 然后还要算下这段区间,和最大值比较。

so,我再搞两个值,一个结点区间的 左端点 连续为 1 的距离,右端点 连续为1 的距离
后面发现还要再添,一个结点区间的 左端点 连续为 0 的距离,右端点 连续为0 的距离,方便反转


现在发现,线段树 就是个 大模拟= =、好像所有的东西都是大模拟。。

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;

const int N=1e5+10;

struct Seg{
    int Left,Right;
    int Flag;       //标记
    int Sum;       //区间1的个数
    int Max_Len;    //区间 连续 1的 最长长度
    int Left_Len1,Right_Len1;  //区间左端点连续为1的距离,右端点 连续为1 的距离
    int Left_Len0,Right_Len0;   //区间左端点连续为0的距离,右端点 连续为0 的距离
}q[N*4];

void Pushdown(int num)
{
    if(!q[num].Flag) return;
    if(q[num].Flag==1)
    {
        q[num<<1].Sum=q[num<<1].Left_Len1=q[num<<1].Right_Len1=q[num<<1].Max_Len=(q[num<<1].Right-q[num<<1].Left+1);
        q[num<<1].Left_Len0=q[num<<1].Right_Len0=0;
        q[num<<1].Flag=1;

        q[num<<1|1].Sum=q[num<<1|1].Left_Len1=q[num<<1|1].Right_Len1=q[num<<1|1].Max_Len=(q[num<<1|1].Right-q[num<<1|1].Left+1);
        q[num<<1|1].Left_Len0=q[num<<1|1].Right_Len0=0;
        q[num<<1|1].Flag=1;

        q[num].Flag=0;
    }
    else
    {
        q[num<<1].Sum=q[num<<1].Left_Len1=q[num<<1].Right_Len1=q[num<<1].Max_Len=0;
        q[num<<1].Left_Len0=q[num<<1].Right_Len0=(q[num<<1].Right-q[num<<1].Left+1);
        q[num<<1].Flag=-1;

        q[num<<1|1].Sum=q[num<<1|1].Left_Len1=q[num<<1|1].Right_Len1=q[num<<1|1].Max_Len=0;
        q[num<<1|1].Left_Len0=q[num<<1|1].Right_Len0=(q[num<<1|1].Right-q[num<<1|1].Left+1);
        q[num<<1|1].Flag=-1;

        q[num].Flag=0;
    }
}

void Pushup(int num)
{
    if(q[num].Sum==(q[num].Right-q[num].Left+1))
    {
        q[num].Flag=1;
        q[num].Left_Len1=q[num].Right_Len1=q[num].Max_Len=q[num].Sum;
        q[num].Left_Len0=q[num].Right_Len0=0;
    }
    else if(!q[num].Sum)
    {
        q[num].Flag=-1;
        q[num].Left_Len1=q[num].Right_Len1=q[num].Max_Len=q[num].Sum;
        q[num].Left_Len0=q[num].Right_Len0=q[num].Right-q[num].Left+1;
    }
    else
    {
        q[num].Flag=0;

        int Max=max(q[num<<1].Max_Len,q[num<<1|1].Max_Len);
        Max=max(q[num<<1].Right_Len1+q[num<<1|1].Left_Len1,Max);
        q[num].Max_Len=Max;

        if(q[num<<1].Left_Len1==(q[num<<1].Right-q[num<<1].Left+1))
        {
            q[num].Left_Len1=q[num<<1].Left_Len1+q[num<<1|1].Left_Len1;
            q[num].Left_Len0=0;
        }
        else
        {
            q[num].Left_Len1=q[num<<1].Left_Len1;

            if(q[num<<1].Left_Len0==(q[num<<1].Right-q[num<<1].Left+1))
                q[num].Left_Len0=q[num<<1].Left_Len0+q[num<<1|1].Left_Len0;
            else
                q[num].Left_Len0=q[num<<1].Left_Len0;
        }

        if(q[num<<1|1].Right_Len1==(q[num<<1|1].Right-q[num<<1|1].Left+1))
        {
            q[num].Right_Len1=q[num<<1].Right_Len1+q[num<<1|1].Right_Len1;
            q[num].Right_Len0=0;
        }
        else
        {
            q[num].Right_Len1=q[num<<1|1].Right_Len1;
            if(q[num<<1|1].Right_Len0==(q[num<<1|1].Right-q[num<<1|1].Left+1))
                q[num].Right_Len0=q[num<<1].Right_Len0+q[num<<1|1].Right_Len0;
            else
                q[num].Right_Len0=q[num<<1|1].Right_Len0;
        }
    }
}

void Build(int num,int Left,int Right)
{
    q[num].Left=Left;q[num].Right=Right;
    if(Left==Right)
    {
        scanf("%d",&q[num].Sum);
        if(q[num].Sum==1) q[num].Flag=1;
        else q[num].Flag=-1;
        q[num].Left_Len1=q[num].Right_Len1=q[num].Max_Len=q[num].Sum;
        q[num].Left_Len0=q[num].Right_Len0=1-q[num].Sum;
        return;
    }
    int Mid=(q[num].Left+q[num].Right)>>1;
    Build(num<<1,Left,Mid);
    Build(num<<1|1,Mid+1,Right);

    q[num].Sum=q[num<<1].Sum+q[num<<1|1].Sum;
    Pushup(num);
}

void Update1(int num,int Left,int Right)
{
    if(q[num].Left>=Left && q[num].Right<=Right)
    {
        q[num].Flag=-1;
        q[num].Left_Len1=q[num].Right_Len1=q[num].Max_Len=q[num].Sum=0;
        q[num].Left_Len0=q[num].Right_Len0=q[num].Right-q[num].Left+1;
        return;
    }
    Pushdown(num);

    int Mid=(q[num].Left+q[num].Right)>>1;
    if(Mid>=Right) Update1(num<<1,Left,Right);
    else if(Mid<Left) Update1(num<<1|1,Left,Right);
    else
    {
        Update1(num<<1,Left,Mid);
        Update1(num<<1|1,Mid+1,Right);
    }

    q[num].Sum=q[num<<1].Sum+q[num<<1|1].Sum;
    Pushup(num);
}

void Update2(int num,int Left,int Right)
{
    if(q[num].Left>=Left && q[num].Right<=Right)
    {
        q[num].Flag=1;
        q[num].Left_Len1=q[num].Right_Len1=q[num].Max_Len=q[num].Sum=(q[num].Right-q[num].Left+1);
        q[num].Left_Len0=q[num].Right_Len0=0;
        return;
    }

    Pushdown(num);

    int Mid=(q[num].Left+q[num].Right)>>1;
    if(Mid>=Right) Update2(num<<1,Left,Right);
    else if(Mid<Left) Update2(num<<1|1,Left,Right);
    else
    {
        Update2(num<<1,Left,Mid);
        Update2(num<<1|1,Mid+1,Right);
    }

    q[num].Sum=q[num<<1].Sum+q[num<<1|1].Sum;
    Pushup(num);
}

void Update3(int num,int Left,int Right)
{
    if(q[num].Left>=Left && q[num].Right<=Right && (q[num].Sum==0||q[num].Sum==(q[num].Right-q[num].Left+1)))
    {
        if(q[num].Sum==(q[num].Right-q[num].Left+1)) q[num].Flag=-1;
        else q[num].Flag=1;
        q[num].Max_Len=q[num].Sum=q[num].Right-q[num].Left+1-q[num].Sum;
        swap(q[num].Right_Len0,q[num].Right_Len1);
        swap(q[num].Left_Len0,q[num].Left_Len1);
        return;
    }

    Pushdown(num);

    int Mid=(q[num].Left+q[num].Right)>>1;
    if(Mid>=Right) Update3(num<<1,Left,Right);
    else if(Mid<Left) Update3(num<<1|1,Left,Right);
    else
    {
        Update3(num<<1,Left,Mid);
        Update3(num<<1|1,Mid+1,Right);
    }

    q[num].Sum=q[num<<1].Sum+q[num<<1|1].Sum;
    Pushup(num);
}

int Query(int num,int Left,int Right)
{
    if(q[num].Left>=Left && q[num].Right<=Right)
        return q[num].Sum;
    Pushdown(num);
    int Mid=(q[num].Left+q[num].Right)>>1;
    if(Mid>=Right)
        return Query(num<<1,Left,Right);
    else if(Mid<Left)
        return Query(num<<1|1,Left,Right);
    else
        return Query(num<<1,Left,Mid)+Query(num<<1|1,Mid+1,Right);
}

int MaxLen(int num,int Left,int Right)
{
    if(q[num].Left>=Left && q[num].Right<=Right) return q[num].Max_Len;
    Pushdown(num);
    int Mid=(q[num].Left+q[num].Right)>>1;
    if(Mid>=Right) return MaxLen(num<<1,Left,Right);
    else if(Mid<Left) return MaxLen(num<<1|1,Left,Right);
    else
    {
        int Len1=MaxLen(num<<1,Left,Mid);
        int Len2=MaxLen(num<<1|1,Mid+1,Right);
        int Len3=min(q[num<<1].Right_Len1,Mid-Left+1) + min(q[num<<1|1].Left_Len1,Right-Mid);
        return max(Len1,max(Len2,Len3));
    }
}

int main()
{
    int n,m,x;
    int Left,Right;
    scanf("%d%d",&n,&m);
    Build(1,1,n);

    while(m--){
        scanf("%d%d%d",&x,&Left,&Right);
        Left++;Right++;
        switch(x)
        {
            case 0: { Update1(1,Left,Right); break;}
            case 1: { Update2(1,Left,Right); break;}
            case 2: { Update3(1,Left,Right); break;}
            case 3: { printf("%d\n",Query(1,Left,Right)); break;}
            case 4: { printf("%d\n",MaxLen(1,Left,Right)); break;}
        }
    }
    return 0;
}






posted @ 2017-03-29 21:32  see_you_later  阅读(271)  评论(0编辑  收藏  举报