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

版权声明:欢迎大家指正错误,有不同观点的欢迎评论,共同进步 https://blog.csdn.net/Sirius_han/article/details/81604156

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;
}

猜你喜欢

转载自blog.csdn.net/Sirius_han/article/details/81604156