hdu3911 Black And White 线段树区间合并

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
题目大概就是说输入0就是查询区间内的1的和,输入1,就把区间内的值异或一遍,那么我选择线段树
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;
const int maxn=100010;
int n,m,sum1[maxn*5],lsum1[maxn*5],rsum1[maxn*5],cover[maxn*5],sum2[maxn*5],lsum2[maxn*5],rsum2[maxn*5];
//lsum1表示当前节点从左往右的最大连续的1的个数,lsum2表示当前节点从左往右的最大连续的0的个数,其他的sum同理 
//记录最大连续的1和0的个数,那么在修改的时候直接交换就行了 
//cover是lazy标签 
inline int Max(int a,int b)//据说这样会快一点 
{
	return a>b?a:b;
}
inline int Min(int a,int b)
{
	return a<b?a:b;
}
void sovle(int rt)
{
	swap(lsum1[rt],lsum2[rt]);
	swap(rsum1[rt],rsum2[rt]);
	swap(sum1[rt],sum2[rt]);
}
void pushup(int rt,int m)
{
	lsum1[rt]=lsum1[rt<<1];
	lsum2[rt]=lsum2[rt<<1];
	if(lsum1[rt<<1]==m-(m>>1))lsum1[rt]+=lsum1[rt<<1|1];
	if(lsum2[rt<<1]==m-(m>>1))lsum2[rt]+=lsum2[rt<<1|1];//左区间的最大值 
	rsum1[rt]=rsum1[rt<<1|1];
	rsum2[rt]=rsum2[rt<<1|1];
	if(rsum1[rt<<1|1]==(m>>1))rsum1[rt]+=rsum1[rt<<1];
	if(rsum2[rt<<1|1]==(m>>1))rsum2[rt]+=rsum2[rt<<1];//右区间的
	sum1[rt]=Max(rsum1[rt<<1]+lsum1[rt<<1|1],Max(sum1[rt<<1],sum1[rt<<1|1]));
	sum2[rt]=Max(rsum2[rt<<1]+lsum2[rt<<1|1],Max(sum2[rt<<1],sum2[rt<<1|1]));//中间向两边的 
}
void pushdown(int rt)
{
	if(cover[rt])
	{
		cover[rt<<1]^=1,cover[rt<<1|1]^=1;
		cover[rt]=0;
		sovle(rt<<1),sovle(rt<<1|1);
	}
}
void build(int l,int r,int rt)//边读边建树,简直6666 
{
	cover[rt]=0;
	if(l==r)
	{
		int j;
		scanf("%d",&j);
		lsum1[rt]=rsum1[rt]=sum1[rt]=j;//简便写法. 
		lsum2[rt]=rsum2[rt]=sum2[rt]=!j;
		return;
	}
	int m=(l+r)>>1;
	build(lson);
	build(rson);
	pushup(rt,r-l+1);
}
void updata(int x,int y,int l,int r,int rt)
{
	if(l>=x&&r<=y)
	{
		cover[rt]^=1;
		sovle(rt);
		return;
	}
	pushdown(rt);
	int m=(l+r)>>1;
	if(x<=m)updata(x,y,lson);
	if(y>m)updata(x,y,rson);
	pushup(rt,r-l+1);
}
int query(int x,int y,int l,int r,int rt)
{
	if(l>=x&&r<=y)return sum1[rt];
	pushdown(rt);
	int m=(l+r)>>1;
	if(x>m)return query(x,y,rson);
	if(y<=m)return query(x,y,lson);
    return Max(Min(m-x+1,rsum1[rt<<1])+Min(y-m,lsum1[rt<<1|1]),Max(query(x,y,lson),query(x,y,rson)));//左右和中间的最大值 
}
int main()
{
	int op,a,b;
	while(~scanf("%d",&n))
	{
		build(1,n,1);
		scanf("%d",&m);
		while(m--)
		{
			scanf("%d%d%d",&op,&a,&b);
			if(op)updata(a,b,1,n,1);
			else printf("%d\n",query(a,b,1,n,1));
		}
	}
	return 0;
}


猜你喜欢

转载自blog.csdn.net/yslcl12345/article/details/50838459