hdu 3911 区间合并+区间查询

Black And White


Time Limit: 9000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)

Total Submission(s): 3638    Accepted Submission(s): 1086


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
 

Source
2011 Multi-University Training Contest 8 - Host by HUST

解释在线段树习题集中有,下面贴出代码,如有可以优化的地方希望指正。


#include <cstdio>
#include <iostream>
#include <queue>
#include <cstring>
#include <vector>
#include <algorithm>

using namespace std;

const int maxn = 100000+10;
int data[maxn];
int setv[4*maxn];
int lb[4*maxn], rb[4*maxn], sb[4*maxn];
int lw[4*maxn], rw[4*maxn], sw[4*maxn];

void pushup(int root, int l, int r){
  int lc = 2*root, rc = 2*root+1;
  int len = r-l+1;
  // 处理黑连块
  lb[root] = lb[lc];
  if(lb[lc] == len-len/2) lb[root] += lb[rc];
  rb[root] = rb[rc];
  if(rb[root] == len/2) rb[root] += rb[lc];
  sb[root] = max(rb[lc]+lb[rc], max(sb[lc], sb[rc]));
  // 右孩子的左边,左孩子的右边
  // 处理白连块
  lw[root] = lw[lc];
  if(lw[lc] == len-len/2) lw[root] += lw[rc];
  rw[root] = rw[rc];
  if(rw[root] == len/2) rw[root] += rw[lc];
  sw[root] = max(rw[lc]+lw[rc], max(sw[lc], sw[rc]));
}

void build(int root, int l, int r){
  int mid = (l+r)/2, lc = 2*root, rc = 2*root+1;
  if(l < r){
    build(lc, l, mid);
    build(rc, mid+1, r);
    pushup(root, l, r);
  }else{
    if(data[l] == 1){
      lb[root] = rb[root] = sb[root] = 1;
      lw[root] = rw[root] = sw[root] = 0;
    }else{
      lb[root] = rb[root] = sb[root] = 0;
      lw[root] = rw[root] = sw[root] = 1;
    }
  }
}

void exchange(int root){
  swap(lb[root], lw[root]);
  swap(rb[root], rw[root]);
  swap(sb[root], sw[root]);
}

void pushdown(int root, int l, int r){
  int lc = 2*root, rc = 2*root+1;
  if(setv[root]){
    setv[lc] ^= 1; setv[rc] ^= 1;
    setv[root] = 0;
    exchange(lc);  exchange(rc);
  }
}

void modify(int root, int l, int r, int x, int y){
  int mid = (l+r)/2, lc = 2*root, rc = 2*root+1;
  if(x <= l && r <= y){
    setv[root] ^= 1;
    exchange(root);
  }else{
    pushdown(root, l, r);
    if(x <= mid) modify(lc, l, mid, x, y);
    if(y > mid) modify(rc, mid+1, r, x, y);
    pushup(root, l, r);
  }
}

// 区间查询
int query(int root, int l, int r, int x, int y){
  int mid = (l+r)/2, lc = 2*root, rc = 2*root+1;
  if(x <= l && r <= y){
    return sb[root];
  }else{
    pushdown(root, l, r);
    int lsum, rsum;
    lsum = rsum = 0;
    if(y <= mid) return query(lc, l, mid, x, y);
    if(x > mid) return query(rc, mid+1, r, x, y);
    lsum = query(lc, l, mid, x, y);
    // 完全在左子树的
    rsum = query(rc, mid+1, r, x, y);
    // 完全在右子树的
    int len = r-l+1;
    int b1 = min(mid-x+1, rb[lc]);
    int b2 = min(y-mid, lb[rc]);
    // 横跨左右子树的,但是右不能重复计算
    return max(max(lsum, rsum), b1+b2);
  }
}


template <class T>
inline void Input(T &x){
  char c; x = 0;
  while((c = getchar()) < '0' || c > '9');
  while(c >= '0' && c <= '9') x = x*10 + (c-'0'), c = getchar();
}

template <class T>
inline void Output(T x){
  if(x > 9) Output(x/10);
  putchar(x%10+'0');
}

int main(){
  int n, m;
  while(scanf("%d", &n) != EOF){
    memset(setv, 0, sizeof(setv));
    for(int i = 1; i <= n; i ++){
      //scanf("%d", &data[i]);
      Input(data[i]);
    }
    build(1, 1, n);
    int a, b, c;
    //scanf("%d", &m);
    Input(m);
    for(int i = 1; i <= m; i ++){
     // scanf("%d%d%d", &a, &b, &c);
     Input(a); Input(b); Input(c);
      if(a == 0){
        int ans = query(1, 1, n, b, c);
        //printf("%d\n", ans);
         Output(ans);  puts("");
      }else{
        modify(1, 1, n, b, c);
      }
    }
  }
  return 0;
}










 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值