Black And White HDU - 3911 (线段树,区间更新)

Black And White

 题目链接:HDU - 3911 

题意:一个01串,两种操作,1   l    r:将区间[l, r]中的1变为0, 0变为1;   0  l   r :求区间[l, r]中最长的连续为1的子串的长度;

思路:当改变区间[l, r]时,相当于对其进行与0的异或运算,同一区间操作两次相当于没有操作;

在区间[l, r]中,令l_one记录由l向右开始最长连续1,l_zero记录由l向右开始最长连续0, r_one记录由r开始向左最长连续1, r_zero记录由r开始向左最长连续0;m_one记录区间内最长连续1;m_zero记录区间内最长连续0;len记录区间长度;

对于一个父节点fa来说,fa的l_one等于其左孩子的l_one;如果左孩子的l_one等于做孩子的区间长度,那么就可以和右孩子的l_one连接;以此类推就可以得到fa的l_zero, r_one, r_zero;

那么,fa的m_one就等于左右孩子中m_one最大的一个,因为左右孩子进行了区间合并,所以左孩子的r_one与右孩子的l_one可以合并,所以fa的m_one还等于左孩子的r_one+右孩子的l_one;以此类推可以得到fa的m_zero; 

每次对区间[l, r]进行操作后,相当于l_one和l_zero交换,r_one和r_zero交换,m_one和m_zero交换;因为1变0,0变1嘛;

#include <bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
struct node{
	int l, r, len;
	int l_one, r_one;
	int l_zero, r_zero;
	int m_one, m_zero;
	int lazy; 
}tr[maxn<<2];
void pushup(int m){
	tr[m].l_one=tr[m<<1].l_one;
	if(tr[m<<1].l_one==tr[m<<1].len) tr[m].l_one+=tr[m<<1|1].l_one;
	tr[m].l_zero=tr[m<<1].l_zero;
	if(tr[m<<1].l_zero==tr[m<<1].len) tr[m].l_zero+=tr[m<<1|1].l_zero;
	
	tr[m].r_one=tr[m<<1|1].r_one;
	if(tr[m<<1|1].r_one==tr[m<<1|1].len) tr[m].r_one+=tr[m<<1].r_one;
	tr[m].r_zero=tr[m<<1|1].r_zero;
	if(tr[m<<1|1].r_zero==tr[m<<1|1].len) tr[m].r_zero+=tr[m<<1].r_zero;
	
	tr[m].m_one=max(tr[m<<1].m_one, tr[m<<1|1].m_one);
	tr[m].m_one=max(tr[m].m_one, tr[m<<1].r_one+tr[m<<1|1].l_one);
	tr[m].m_zero=max(tr[m<<1].m_zero, tr[m<<1|1].m_zero);
	tr[m].m_zero=max(tr[m].m_zero, tr[m<<1].r_zero+tr[m<<1|1].l_zero);
}
void pushdown(int m){
	if(tr[m].lazy){
		tr[m<<1].lazy^=1;
		tr[m<<1|1].lazy^=1;
		
		swap(tr[m<<1].m_one, tr[m<<1].m_zero);
		swap(tr[m<<1].l_one, tr[m<<1].l_zero);
		swap(tr[m<<1].r_one, tr[m<<1].r_zero);
		
		swap(tr[m<<1|1].m_one, tr[m<<1|1].m_zero);
		swap(tr[m<<1|1].l_one, tr[m<<1|1].l_zero);
		swap(tr[m<<1|1].r_one, tr[m<<1|1].r_zero);
		
		tr[m].lazy=0;
	}
}
void build(int m, int l, int r){
	tr[m].l=l;
	tr[m].r=r;
	tr[m].lazy=0;
	tr[m].len=r-l+1;
	if(l==r){
		int x;
		scanf("%d", &x);
		if(x){
			tr[m].l_one=tr[m].r_one=tr[m].m_one=1;
			tr[m].l_zero=tr[m].r_zero=tr[m].m_zero=0;
		}
		else{
			tr[m].l_one=tr[m].r_one=tr[m].m_one=0;
			tr[m].l_zero=tr[m].r_zero=tr[m].m_zero=1;
		}
		return;
	}
	int mid=(l+r)>>1;
	build(m<<1, l, mid);
	build(m<<1|1, mid+1, r);
	pushup(m);
}
void updata(int m, int l, int r){
	if(tr[m].l==l&&tr[m].r==r){
		swap(tr[m].l_one, tr[m].l_zero);
		swap(tr[m].r_one, tr[m].r_zero);
		swap(tr[m].m_one, tr[m].m_zero);
		tr[m].lazy^=1;//这里是异或,因为连续操作偶数次相当于没有操作;
		return;
	}
	pushdown(m);
	int mid=(tr[m].l+tr[m].r)>>1;
	if(r<=mid) updata(m<<1, l, r);
	else if(l>mid) updata(m<<1|1, l, r);
	else{
		updata(m<<1, l, mid);
		updata(m<<1|1, mid+1, r);
	}
	pushup(m);
}
int query(int m, int l, int r){
	if(tr[m].l==l&&tr[m].r==r){
		return tr[m].m_one;
	}
	pushdown(m);
	int mid=(tr[m].l+tr[m].r)>>1;
	int temp;
	if(r<=mid) temp=query(m<<1, l, r);
	else if(l>mid) temp=query(m<<1|1, l, r);
	else{
		int lmax=query(m<<1, l, mid);
		int rmax=query(m<<1|1, mid+1, r);
		int mm=min(tr[m<<1].r_one, mid-l+1)+min(tr[m<<1|1].l_one, r-mid);
		temp=max(max(lmax, rmax), mm);
	}
	pushup(m);
	return temp;
}
int main(){
	int n, m, op, l, r;
	while(~scanf("%d", &n)){
		build(1, 1, n);
		scanf("%d", &m);
		while(m--){
			scanf("%d%d%d", &op, &l, &r);
			if(op){
				updata(1, l, r);
			}
			else printf("%d\n", query(1, l, r));
		}
	}
	return 0;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值