Sequence operation HDU - 3397 (线段树,区间更新, 区间合并)

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

Sequence operation

 题目链接:HDU - 3397 

题意: HDU - 3911 的升级版;

给出一个01串,5种操作:

0 L R:区间[L ,R]全置为0;

1 L R:区间[L, R]全置为1;

2 L R :区间[L, R]中0变1,1变0;

3 L R:求区间[L, R]中1的总个数;

4 L R:求区间[L, R]中连续1的最长长度;

可以先看HDU-3911的题解,更容易理解一些:HDU-3911题解

#include <bits/stdc++.h>
using namespace std;
const int maxn=1e6+10;
struct node{
	int l, r, len;//l, r表示区间范围, len表示区间长度; 
	int l_one, l_zero, r_one, r_zero;//l_表示由l开始向右连续的1或0(称之为左连续), r_表示由r开始向左连续的1或0(称之为右连续); 
	int m_one, m_zero, n_one, n_zero;//m_表示区间内最长的连续的1或0(称之为最大连续), n_表示区间内1或0的个数;
	int lazy0, lazy1, lazy2;//lazy0表示0操作(全置为0), lazy1表示1操作(全置为1), lazy2表示2操作(0变1, 1变0); 
}tr[maxn<<2];
void pushup(int m){
	//1, 0的总个数就是左右孩子相加; 
	tr[m].n_one=tr[m<<1].n_one+tr[m<<1|1].n_one;
	tr[m].n_zero=tr[m<<1].n_zero+tr[m<<1|1].n_zero;
	//如果左孩子的左连续等于左孩子区间大小, 那么左孩子的左连续就可以和右孩子的左连续合并; 
	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;
	//1, 0的最大连续是左右孩子最大连续中的最大值,最后再将左孩子的右连续与右孩子的左连续合并, 比较; 
	tr[m].m_one=max(max(tr[m<<1].m_one, tr[m<<1|1].m_one), tr[m<<1].r_one+tr[m<<1|1].l_one);
	tr[m].m_zero=max(max(tr[m<<1].m_zero, tr[m<<1|1].m_zero), tr[m<<1].r_zero+tr[m<<1|1].l_zero); 
}
//0操作: 
void pushdown0(int m){
	if(tr[m].lazy0){
		tr[m<<1].lazy0=tr[m<<1|1].lazy0=1;
		tr[m<<1].lazy1=tr[m<<1].lazy2=tr[m<<1|1].lazy1=tr[m<<1|1].lazy2=0;
		
		tr[m<<1].n_one=tr[m<<1|1].n_one=0;
		tr[m<<1].n_zero=tr[m<<1].len;
		tr[m<<1|1].n_zero=tr[m<<1|1].len;
		
		tr[m<<1].m_one=tr[m<<1|1].m_one=0;
		tr[m<<1].m_zero=tr[m<<1].len;
		tr[m<<1|1].m_zero=tr[m<<1|1].len;
		
		tr[m<<1].l_one=tr[m<<1].r_one=tr[m<<1|1].l_one=tr[m<<1|1].r_one=0;
		tr[m<<1].l_zero=tr[m<<1].r_zero=tr[m<<1].len;
		tr[m<<1|1].l_zero=tr[m<<1|1].r_zero=tr[m<<1|1].len;
		
		tr[m].lazy0=0;
	}
}
//1操作: 
void pushdown1(int m){
	if(tr[m].lazy1){
		tr[m<<1].lazy1=tr[m<<1|1].lazy1=1;
		tr[m<<1].lazy0=tr[m<<1].lazy2=tr[m<<1|1].lazy0=tr[m<<1|1].lazy2=0;
		
		tr[m<<1].n_zero=tr[m<<1|1].n_zero=0;
		tr[m<<1].n_one=tr[m<<1].len;
		tr[m<<1|1].n_one=tr[m<<1|1].len;
		
		tr[m<<1].m_zero=tr[m<<1|1].m_zero=0;
		tr[m<<1].m_one=tr[m<<1].len;
		tr[m<<1|1].m_one=tr[m<<1|1].len;
	
		tr[m<<1].l_zero=tr[m<<1].r_zero=tr[m<<1|1].l_zero=tr[m<<1|1].r_zero=0;
		tr[m<<1].l_one=tr[m<<1].r_one=tr[m<<1].len;
		tr[m<<1|1].l_one=tr[m<<1|1].r_one=tr[m<<1|1].len;
		
		tr[m].lazy1=0;
	}
}
//2操作: 
void pushdown2(int m){
	if(tr[m].lazy2){
		tr[m<<1].lazy2^=1;
		tr[m<<1|1].lazy2^=1;
		
		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].m_one, tr[m<<1].m_zero);
		swap(tr[m<<1].n_one, tr[m<<1].n_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);
		swap(tr[m<<1|1].m_one, tr[m<<1|1].m_zero);
		swap(tr[m<<1|1].n_one, tr[m<<1|1].n_zero); 
		
		tr[m].lazy2=0;
	}
}
void build(int m, int l, int r){
	tr[m].l=l;
	tr[m].r=r;
	tr[m].lazy0=tr[m].lazy1=tr[m].lazy2=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=tr[m].n_one=1;
			tr[m].l_zero=tr[m].r_zero=tr[m].m_zero=tr[m].n_zero=0;
		}
		else{
			tr[m].l_one=tr[m].r_one=tr[m].m_one=tr[m].n_one=0;
			tr[m].l_zero=tr[m].r_zero=tr[m].m_zero=tr[m].n_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, int op){
	if(tr[m].l==l&&tr[m].r==r){
		if(op==2){
			tr[m].lazy2^=1;
			//如果是2操作, 就先更新孩子节点; 
			pushdown0(m);
			pushdown1(m);
			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);
			swap(tr[m].n_one, tr[m].n_zero);	
		}
		else if(op==0){
			tr[m].l_one=tr[m].r_one=tr[m].n_one=tr[m].m_one=0;
			tr[m].l_zero=tr[m].r_zero=tr[m].m_zero=tr[m].n_zero=tr[m].len;
			tr[m].lazy0=1;
			tr[m].lazy1=tr[m].lazy2=0;
		}		
		else{
			tr[m].l_one=tr[m].r_one=tr[m].n_one=tr[m].m_one=tr[m].len;
			tr[m].l_zero=tr[m].r_zero=tr[m].m_zero=tr[m].n_zero=0;
			tr[m].lazy1=1;
			tr[m].lazy0=tr[m].lazy2=0;
		}
		return;
	}
	pushdown0(m);
	pushdown1(m);
	pushdown2(m);
	int mid=(tr[m].l+tr[m].r)>>1;
	if(r<=mid) updata(m<<1, l, r, op);
	else if(l>mid) updata(m<<1|1, l, r, op);
	else{
		updata(m<<1, l, mid, op);
		updata(m<<1|1, mid+1, r, op);
	}
	pushup(m);
}
int query_m(int m, int l, int r){
	if(tr[m].l==l&&tr[m].r==r){
		return tr[m].m_one;
	}
	pushdown0(m);
	pushdown1(m);
	pushdown2(m);
	int mid=(tr[m].l+tr[m].r)>>1;
	int temp;
	if(r<=mid) temp=query_m(m<<1, l, r);
	else if(l>mid) temp=query_m(m<<1|1, l, r);
	else{
		int lmax=query_m(m<<1, l, mid);
		int rmax=query_m(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 query_n(int m, int l, int r){
	if(tr[m].l==l&&tr[m].r==r){
		return tr[m].n_one;
	}
	pushdown0(m);
	pushdown1(m);
	pushdown2(m);
	int mid=(tr[m].l+tr[m].r)>>1;
	int temp;
	if(r<=mid) temp=query_n(m<<1, l, r);
	else if(l>mid) temp=query_n(m<<1|1, l, r);
	else temp=query_n(m<<1, l, mid)+query_n(m<<1|1, mid+1, r); 
	pushup(m);
	return temp;
}
int main(){
	int T;
	scanf("%d", &T);
	while(T--){
		int n, m, op, l, r;
		scanf("%d%d", &n, &m);
		build(1, 1, n);
		while(m--){
			scanf("%d%d%d", &op, &l, &r);
			l++, r++;
			if(op==0) updata(1, l, r, 0);
			else if(op==1) updata(1, l, r, 1);
			else if(op==2) updata(1, l, r, 2);
			else if(op==3) printf("%d\n", query_n(1, l, r));
			else printf("%d\n", query_m(1, l, r));
		}
	}
	return 0;
}

猜你喜欢

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