HDOJ 3911 Black And White 【线段树 区间合并】

Black And White

Time Limit: 9000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 4401    Accepted Submission(s): 1280


Problem Description
There are a bunch of stones on the beach; Stone color is white or black. Little Sheep has a magic brush, she can change the color of a continuous stone, black to white, white to black. Little Sheep like black very much, so she want to know the longest period of consecutive black stones in a range [i, j].
 


Input
  There are multiple cases, the first line of each case is an integer n(1<= n <= 10^5), followed by n integer 1 or 0(1 indicates black stone and 0 indicates white stone), then is an integer M(1<=M<=10^5) followed by M operations formatted as x i j(x = 0 or 1) , x=1 means change the color of stones in range[i,j], and x=0 means ask the longest period of consecutive black stones in range[i,j]
 


Output
When x=0 output a number means the longest length of black stones in range [i,j].
 


Sample Input
  
  
4 1 0 1 0 5 0 1 4 1 2 3 0 1 4 1 3 3 0 4 4
 


Sample Output
  
  
1 2 0


恩,题目大意就是说,一排石头只有黑色和白色,然后小羊的画笔可以将连续的黑色石头变为白色,白色石头变为黑色,然后 1 i j 表示改变从 i 到 j 区间内石头的颜色,0 i j 表示询问从 i 到 j 最长的连续的黑色石头的长度


//ls1表示从左边数连续的1的个数 rs1从右边数 ms1总的
#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxn 100000+10
using namespace std;
struct lnode
{
    int l,r,len;
    int ls1,ls0,rs1,rs0,ms0,ms1;
    int mark;
}node[maxn<<2];
int rec[maxn];
void pushup(int o)
{
    node[o].ls1=node[o<<1].ls1;//首先从左边数连续1的个数等于左子树从左边数
    if(node[o<<1].ls1==node[o<<1].len)//若它等于左子树的长度则可以加上右子树从左边数的
        node[o].ls1+=node[o<<1|1].ls1;
    node[o].rs1=node[o<<1|1].rs1;
    if(node[o<<1|1].rs1==node[o<<1|1].len)
        node[o].rs1+=node[o<<1].rs1;
    node[o].ms1=max(max(node[o<<1].ms1,node[o<<1|1].ms1),(node[o<<1].rs1+node[o<<1|1].ls1));//这里比较左子树和右子树以及两子树中间的
    node[o].ls0=node[o<<1].ls0;
    if(node[o<<1].ls0==node[o<<1].len)
        node[o].ls0+=node[o<<1|1].ls0;
    node[o].rs0=node[o<<1|1].rs0;
    if(node[o<<1|1].rs0==node[o<<1|1].len)
        node[o].rs0+=node[o<<1].rs0;
    node[o].ms0=max(max(node[o<<1].ms0,node[o<<1|1].ms0),(node[o<<1].rs0+node[o<<1|1].ls0));
}
void pushdown(int o)
{
    if(node[o].mark==1)
    {
        node[o<<1].mark^=1;//至于这里的异或现在还不太懂。。。。
        node[o<<1|1].mark^=1;
        node[o].mark=0;
        swap(node[o<<1].ls1,node[o<<1].ls0);//直接将1变为0了
        swap(node[o<<1].rs1,node[o<<1].rs0);
        swap(node[o<<1].ms1,node[o<<1].ms0);
        swap(node[o<<1|1].ls1,node[o<<1|1].ls0);
        swap(node[o<<1|1].rs1,node[o<<1|1].rs0);
        swap(node[o<<1|1].ms1,node[o<<1|1].ms0);
    }
}
void build(int o,int l,int r)
{
    node[o].l=l;
    node[o].r=r;
    node[o].len=r-l+1;
    node[o].mark=0;
    if(l==r)
    {
        node[o].ls1=node[o].rs1=node[o].ms1=rec[l]?1:0;
        node[o].ls0=node[o].rs0=node[o].ms0=rec[l]?0:1;
        return ;
    }
    int mid=(l+r)>>1;
    build(o<<1,l,mid);
    build(o<<1|1,mid+1,r);
    pushup(o);
}
void update(int o,int l,int r)
{
    if(node[o].l==l&&node[o].r==r)
    {
        node[o].mark^=1;
        swap(node[o].ls1,node[o].ls0);
        swap(node[o].rs1,node[o].rs0);
        swap(node[o].ms1,node[o].ms0);
        return ;
    }
    pushdown(o);
    int mid=(node[o].l+node[o].r)>>1;
    if(r<=mid)
        update(o<<1,l,r);
    else if(l>mid)
        update(o<<1|1,l,r);
    else
    {
        update(o<<1,l,mid);
        update(o<<1|1,mid+1,r);
    }
    pushup(o);
}
int query(int o,int l,int r)
{
    if(node[o].l==l&&node[o].r==r)
        return node[o].ms1;
    pushdown(o);
    int mid=(node[o].l+node[o].r)>>1;
    if(r<=mid)
        return query(o<<1,l,r);
    else if(l>mid)
        return query(o<<1|1,l,r);
    else
    {
        int ls=query(o<<1,l,mid);
        int rs=query(o<<1|1,mid+1,r);
        int aa=node[o<<1].rs1;
        if(aa>mid-l+1)//左子树的最长的1不可能分布在从mid到 l 的左边,最长到 l 
            aa=mid-l+1;
        int bb=node[o<<1|1].ls1;
        if(bb>r-mid)//这里因为像上面一样加了1让我找错找了好久。。。因为右子树不包括mid所以不能加1
            bb=r-mid;
        return max(max(ls,rs),(aa+bb));//aa+bb 为中间的
    }
}
int main()
{
    int n,m,x,a,b;
    while(~scanf("%d",&n))
    {
        for(int i=1;i<=n;++i)
            scanf("%d",&rec[i]);
        build(1,1,n);
        scanf("%d",&m);
        while(m--)
        {
            scanf("%d%d%d",&x,&a,&b);
            if(x==0)
                printf("%d\n",query(1,a,b));
            else if(x==1)
                update(1,a,b);
        }
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值