hdu 3911 Black and White 线段树维护01序列

Black And White

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

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

题意:给你一些01序列,再给你一些询问。当询问为1的时候,把给定区间内所有的0变为1,1边为0,当询问为0的时候,输出所求区间中最长的连续的1的个数。

用线段树。
维护的东西:左右区间最长的1序列和左右区间最长的0序列。左区间最右端有几个连续的1/0,右区间有几个连续的1/0,以及lazy标记,以及最长的0/1序列的答案。
每次比较左区间最大值和右区间的最大值,以及左区间最右端和右区间最左端的和,最大的作为大区间的答案。
每次lazy标记下传就交换01串的答案就行了。
我果然还是只会线段树的傻逼题。。。

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;

const int N = 1000010;

int a[N];

inline int Max(int a,int b){
    return a>b?a:b;
}

struct node{
    int mmax1,mmax0;
    int flag;
    int lm1,rm1;//分别表示左区间最长的1的串和右区间的最长的1的串 
    int lm0,rm0;
    int l,r;
}tree[N];

void pushup(int root){
    int llen=tree[root<<1].r-tree[root<<1].l+1;
    int rlen=tree[root<<1|1].r-tree[root<<1|1].l+1;

    tree[root].lm1=tree[root<<1].lm1;
    if(tree[root<<1].lm1==llen) tree[root].lm1+=tree[root<<1|1].lm1;
    tree[root].rm1=tree[root<<1|1].rm1;
    if(tree[root<<1|1].rm1==rlen) tree[root].rm1+=tree[root<<1].rm1;

    int c=Max(tree[root<<1].mmax1,tree[root<<1|1].mmax1);
    int d=tree[root<<1|1].lm1+tree[root<<1].rm1;
    tree[root].mmax1=Max(c,d);

    tree[root].lm0=tree[root<<1].lm0;
    if(tree[root<<1].lm0==llen) tree[root].lm0+=tree[root<<1|1].lm0;
    tree[root].rm0=tree[root<<1|1].rm0;
    if(tree[root<<1|1].rm0==rlen) tree[root].rm0+=tree[root<<1].rm0;
    c=Max(tree[root<<1].mmax0,tree[root<<1|1].mmax0);
    d=tree[root<<1|1].lm0+tree[root<<1].rm0;
    tree[root].mmax0=Max(c,d);
}

void pushdown(int root){
    int flag = tree[root].flag;
    if(flag){
        tree[root<<1].flag ^= 1;
        tree[root<<1|1].flag ^= 1;
        swap(tree[root<<1].mmax1,tree[root<<1].mmax0);
        swap(tree[root<<1].lm1,tree[root<<1].lm0);
        swap(tree[root<<1].rm1,tree[root<<1].rm0);

        swap(tree[root<<1|1].mmax1,tree[root<<1|1].mmax0);
        swap(tree[root<<1|1].lm1,tree[root<<1|1].lm0);
        swap(tree[root<<1|1].rm1,tree[root<<1|1].rm0);
        tree[root].flag=0;  
    }
}

void build(int root,int l,int r){
    tree[root].l=l,tree[root].r=r;
    if(l==r){
        if(a[l]==1){
           tree[root].mmax1=tree[root].lm1=tree[root].rm1=a[l]&1;
           tree[root].mmax0=tree[root].lm0=tree[root].rm0=a[l]^1;
        }
        else{
           tree[root].mmax1=tree[root].lm1=tree[root].rm1=0;//a[l]&1;
           tree[root].mmax0=tree[root].lm0=tree[root].rm0=1;//a[l]^1;           
        }
        tree[root].flag=0;
        return ;
    }
    int mid=(l+r)>>1;
    build(root<<1,l,mid);
    build(root<<1|1,mid+1,r);
    tree[root].flag=0;
    pushup(root);
}

void modify(int root,int pos,int val){
    int l=tree[root].l,r=tree[root].r;
    if(pos==l&&val==r){
        tree[root].flag ^= 1;
        swap(tree[root].mmax1,tree[root].mmax0);
        swap(tree[root].lm1,tree[root].lm0);
        swap(tree[root].rm1,tree[root].rm0);
        return ;
    }
    int mid=l+r>>1;
    pushdown(root);
    if(val<=mid) modify(root<<1,pos,val);
    else if(pos>mid) modify(root<<1|1,pos,val);
    else{
        modify(root<<1,pos,mid);
        modify(root<<1|1,mid+1,val);
    }
    pushup(root);
}
int query(int root,int pos,int val){
    int l=tree[root].l,r=tree[root].r;
    if(l==pos&&r==val) return tree[root].mmax1;
    pushdown(root);
    int mid=(l+r)>>1;
    if(val<=mid) return query(root<<1,pos,val);
    if(pos>mid) return query(root<<1|1,pos,val);
    int ll=query(root<<1,pos,mid);
    int rl=query(root<<1|1,mid+1,val);

    int a=tree[root<<1].rm1;
    if(a>tree[root<<1].r-pos+1) a=tree[root<<1].r-pos+1;

    int b=tree[root<<1|1].lm1;
    if(b>val-tree[root<<1|1].l+1) b=val-tree[root<<1|1].l+1;

    int ans = Max(ll,Max(rl,a+b));
    return ans; 
}

int main(){
    int n,m,x,l,r;
    while(~scanf("%d",&n)){
      for(register int i=1;i<=n;i++)
          scanf("%d",&a[i]);
      build(1,1,n);
      scanf("%d",&m);
      for(register int i=1;i<=m;i++){
          scanf("%d%d%d",&x,&l,&r);
          if(x==0) printf("%d\n",query(1,l,r));
          else if(x==1) modify(1,l,r);
      }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值