HDU 3911 Black And White(线段树区间合并)

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

线段树区间合并:对于每个区间[l,r]所对应的rs,我们给出6个量:

lmax_1:左起的1的最大前缀,lmax_0:左起的0的最大前缀;

rmax_1:右起的1的最大后缀rmax_0:右起的0的最大后缀;

max_1:区间的1的最大连续值,max_0:区间的0的最大连续值

我们的任务就是不断地更新求值。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<string>
#include<iostream>
#include<queue>
#include<cmath>
#include<map>
#include<stack>
#include<bitset>
using namespace std;
#define REPF( i , a , b ) for ( int i = a ; i <= b ; ++ i )
#define REP( i , n ) for ( int i = 0 ; i < n ; ++ i )
#define CLEAR( a , x ) memset ( a , x , sizeof a )
typedef long long LL;
typedef pair<int,int>pil;
const int mod = 1000000007;
const int maxn=1e5+10;
int lmax_1[maxn<<2],rmax_1[maxn<<2];
int lmax_0[maxn<<2],rmax_0[maxn<<2];
int max_1[maxn<<2],max_0[maxn<<2];
int col[maxn<<2];
int n,m,os;
void pushup(int rs,int m)
{
    lmax_1[rs]=lmax_1[rs<<1];//处理左边一类前缀
    lmax_0[rs]=lmax_0[rs<<1];
    if(lmax_1[rs<<1]==m-(m>>1))  lmax_1[rs]+=lmax_1[rs<<1|1];
    if(lmax_0[rs<<1]==m-(m>>1))  lmax_0[rs]+=lmax_0[rs<<1|1];

    rmax_1[rs]=rmax_1[rs<<1|1];//处理右边一类后缀
    rmax_0[rs]=rmax_0[rs<<1|1];
    if(rmax_1[rs<<1|1]==(m>>1))  rmax_1[rs]+=rmax_1[rs<<1];
    if(rmax_0[rs<<1|1]==(m>>1))  rmax_0[rs]+=rmax_0[rs<<1];

    max_1[rs]=max(max_1[rs<<1],max_1[rs<<1|1]);//处理整个区间的值
    max_1[rs]=max(max_1[rs],rmax_1[rs<<1]+lmax_1[rs<<1|1]);
    max_0[rs]=max(max_0[rs<<1],max_0[rs<<1|1]);
    max_0[rs]=max(max_0[rs],rmax_0[rs<<1]+lmax_0[rs<<1|1]);
}
void work(int rs)
{
    swap(lmax_1[rs],lmax_0[rs]);
    swap(rmax_1[rs],rmax_0[rs]);
    swap(max_1[rs],max_0[rs]);
}
void push_down(int rs)
{
    if(col[rs])
    {
        col[rs<<1]^=1;col[rs<<1|1]^=1;
        col[rs]=0;work(rs<<1);work(rs<<1|1);
    }
}
void build(int rs,int l,int r)
{
    col[rs]=0;
    if(l==r)
    {
        scanf("%d",&os);
        if(os==1)
        {
            lmax_1[rs]=rmax_1[rs]=max_1[rs]=1;
            lmax_0[rs]=rmax_0[rs]=max_0[rs]=0;
        }
        else
        {
            lmax_1[rs]=rmax_1[rs]=max_1[rs]=0;
            lmax_0[rs]=rmax_0[rs]=max_0[rs]=1;
        }
        return ;
    }
    int mid=(l+r)>>1;
    build(rs<<1,l,mid);
    build(rs<<1|1,mid+1,r);
    pushup(rs,r-l+1);
}
void update(int x,int y,int l,int r,int rs)
{
    if(l>=x&&r<=y)
    {
        col[rs]^=1;
        work(rs);//交换值
        return ;
    }
    push_down(rs);
    int mid=(l+r)>>1;
    if(x<=mid)  update(x,y,l,mid,rs<<1);
    if(y>mid)  update(x,y,mid+1,r,rs<<1|1);
    pushup(rs,r-l+1);
}
int query(int x,int y,int l,int r,int rs)
{
    if(l>=x&&r<=y)
        return max_1[rs];
    push_down(rs);
    int mid=(l+r)>>1;
    if(x>mid)  return query(x,y,mid+1,r,rs<<1|1);
    if(y<=mid)  return query(x,y,l,mid,rs<<1);
    int t1=query(x,y,l,mid,rs<<1);
    int t2=query(x,y,mid+1,r,rs<<1|1);
    int r1=min(mid-x+1,rmax_1[rs<<1]);//以mid为分割点
    int r2=min(y-mid,lmax_1[rs<<1|1]);
    int res=max(max(t1,t2),r1+r2);
    return res;
}
int main()
{
    int op,x,y;
    while(~scanf("%d",&n))
    {
       build(1,1,n);
       scanf("%d",&m);
       while(m--)
       {
           scanf("%d%d%d",&op,&x,&y);
           if(op==1)
               update(x,y,1,n,1);
           else
               printf("%d\n",query(x,y,1,n,1));
       }
    }
    return 0;
}
时间: 2024-12-25 15:44:19

HDU 3911 Black And White(线段树区间合并)的相关文章

HDU 3911 Black And White (线段树区间合并 + lazy标记)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3911 给你n个数0和1,m个操作: 0操作  输出l到r之间最长的连续1的个数 1操作  将l到r之间的0变1,1变0 区间合并的模版题,结构体中的lsum1表示从此区间最左端开始连续1的个数,rsum1表示从此区间最右端开始连续1的个数,sum1表示此区间连续1的个数最长是多少.lsum0,rsum0,sum0也是如此.每一次1的操作将区间内lazy标记与1异或一次,异或两次就说明操作抵消了.然后

hdu 3911 Black And White(线段树)

题目连接:hdu 3911 Black And White 题目大意:给定一个序列,然后有M次操作: 0 l r:表示询问l,r中最大连续1的个数 1 l r:表示将l,r区间上的数取反 解题思路:线段树的一种题型,区间合并,因为有一个取反的操作,所以对于每个节点要维护6个值,包括连续0,1最长序列的长度,左边和右边的最长连续长度.需要注意的是,如果询问的区间最大值是从R[lson] + L[rson]来到,要判断是否比长度大于r - l + 1.一开始没注意,所以WA了,上网搜了下别人的题解,

HDU 3911 Black and White (线段树,区间翻转)

  [题目地址] vjudge HDU [题目大意] 海滩上有一堆石头. 石头的颜色是白色或黑色. 小肥羊拥有魔术刷,她可以改变连续石的颜色,从黑变白,从白变黑. 小肥羊非常喜欢黑色,因此她想知道范围[i,j]中连续的黑色石头的最长时间. 有多种情况,每种情况的第一行是整数n(1 <= n <= 10 ^ 5),后跟n个整数1或0(1表示黑石头,0表示白石头),然后是整数 M(1 <= M <= 10 ^ 5)后跟M个运算,格式为xij(x = 0或1),x = 1表示更改范围[i

HDU 2871 Memory Control(线段树&#183;区间合并&#183;Vector)

题意  模拟内存申请  有n个内存单元  有以下4种操作 Reset  将n个内存单元全部清空 New x  申请一个长度为x的连续内存块  申请成功就输出左端 Free x  将x所在的内存块空间释放  释放成功输出释放的内存始末位置 Get x  输出第x个内存块的起始位置 Reset 和 New 都是基本的区间合并知识  比较简单  Free和Get需要知道内层块的位置  所以我们在New的时候要将申请的内存块的始末位置都存起来  两个内层块不会相交  这样就能通过二分找到需要的内层块了

hdu3911 Black And White(线段树区间合并)

题意:给一个由0,1组成的序列,有两种操作,一种是翻转给定区间的数(0->1,1->0),另一种是查询给定区间内由1组成的子串的最大长度.重点在区间合并和延迟标记. #include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<queue> #include<set> #i

(简单) HDU 3397 Sequence operation,线段树+区间合并。

Problem Description lxhgww got a sequence contains n characters which are all '0's or '1's. We have five operations here: Change operations: 0 a b change all characters into '0's in [a , b] 1 a b change all characters into '1's in [a , b] 2 a b chang

hdu3911 线段树 区间合并

1 //Accepted 3911 750MS 9872K 2 //线段树 区间合并 3 #include <cstdio> 4 #include <cstring> 5 #include <iostream> 6 #include <queue> 7 #include <cmath> 8 #include <algorithm> 9 using namespace std; 10 /** 11 * This is a documen

HDU 3911 线段树区间合并

北京赛区快了,准备袭击数据结构和图论.倒计时 18天,线段树区间合并.维护一个最长连续.. 题意:给一个01串,以下有一些操作,问区间最长的连续的1的个数 思路:非常裸的线段树区间合并 #include<iostream> #include<cstdio> #include<map> #include<set> #include<cmath> #define lson id << 1 #define rson id <<

HDU 3911 Black And White 分段树 题解

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 wan