HDU 3911 Black And White 2011 Multi-University Training Contest 8 - Host by HUST 线段树应用

/*
1表示黑,0表示白,
0 a b 表示询问区间[a,b]中最长连续黑石子的数目
1 a b 表示翻转区间[a,b]内的黑白
*/
#include <iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<ctime>
#include<map>
#include<vector>
using namespace std;
const int N=100009;
int n,m;
int a[N];
struct Node
{
	int L,R,len;//区间
	int flag;//flag为松弛标志
	int num0,max0,left0,right0;
	int num1,max1,left1,right1;
	//num1区间黑色的数目  max1最长连续黑的数目   left1区间左侧连续黑的数目
}node[N*4];
int max(int x,int y)
{
	return x>y?x:y;
}
void lazy(int i)
{
	int tmp;
	
	int lt = 2*i,rt = 2*i+1;
    node[i].num0 = node[lt].num0+node[rt].num0;
    node[i].num1 = node[lt].num1+node[rt].num1;
    
    
    node[i].max0 =max( node[lt].max0,node[rt].max0);
    node[i].max0 = max(node[i].max0, node[lt].right0+ node[rt].left0);
    
    
    node[i].left0 = node[lt].left0;
    node[i].right0 = node[rt].right0;
    
    
    if(node[lt].left0 == node[lt].len)//如果左子区间全0,那么它的左边连续0的个数就是左子区间加上右子区间的左边0的个数,下同。。。
        node[i].left0 += node[rt].left0;
    
    
     if(node[rt].right0 == node[rt].len)
        node[i].right0 += node[lt].right0;
    
    
    
    node[i].max1 =max( node[lt].max1,node[rt].max1);
    node[i].max1 = max(node[i].max1, node[lt].right1+ node[rt].left1);
    
    
    node[i].left1 = node[lt].left1;
    node[i].right1 = node[rt].right1;
    
    
      if(node[lt].left1 == node[lt].len)
        node[i].left1 += node[rt].left1;
    
    
     if(node[rt].right1 == node[rt].len)
        node[i].right1 += node[lt].right1;
	

}
void create(int t,int L,int R)
{
	int mid=(L+R)>>1,tmp;
	node[t].L=L;
	node[t].R=R;
	node[t].len=R-L+1;
	if(L==R)
	{
		node[t].left0=node[t].right0=node[t].max0=node[t].num0=a[R]^1;
		node[t].left1=node[t].right1=node[t].max1=node[t].num1=a[R];
		node[t].flag=0;
		return ;
	}
	create(t<<1,L,mid);create((t<<1)+1,mid+1,R);
	lazy(t);
	node[t].flag=0;
}

void down(int t)//将t释放至其子树
{

		swap(node[t<<1].max1,node[t<<1].max0);
		swap(node[t<<1].num0,node[t<<1].num1);
		swap(node[t<<1].left0,node[t<<1].left1);
		swap(node[t<<1].right0,node[t<<1].right1);
	
		swap(node[(t<<1)+1].max1,node[(t<<1)+1].max0);
		swap(node[(t<<1)+1].num0,node[(t<<1)+1].num1);
		swap(node[(t<<1)+1].left0,node[(t<<1)+1].left1);
		swap(node[(t<<1)+1].right0,node[(t<<1)+1].right1);
	if(node[t].L!=node[t].R)
	{
		node[t<<1].flag ^=1;
		node[(t<<1)+1].flag ^=1;
	}
}
void update(int t,int L,int R) //更新区间[L,R],使区间黑变白,白变黑
{
	int mid=(node[t].R+node[t].L)>>1,tmp;
	if(node[t].L==L&&node[t].R==R)
	{
		node[t].flag ^=1;
		swap(node[t].max1,node[t].max0);
		swap(node[t].num0,node[t].num1);
		swap(node[t].left0,node[t].left1);
		swap(node[t].right0,node[t].right1);
		return ;
	}
	if(node[t].flag)//向下松弛操作
	{
		node[t].flag=0;
		down(t);
	}
	if(R<=mid) update(t<<1,L,R);
	else if(L>mid) update((t<<1)+1,L,R);
	else {update(t<<1,L,mid),update((t<<1)+1,mid+1,R);}
	

	lazy(t);
}

int query(int t,int L,int R)
{
	int mid=(node[t].R+node[t].L)>>1,tmp;
	if(node[t].L==L&&node[t].R==R)
	{
		return node[t].max1;
	}
		if(node[t].flag)//向下松弛操作
		{
			node[t].flag=0;
			down(t);
		}
	if(R<=mid)tmp=query(t<<1,L,R);
	else if(L>mid)tmp=query((t<<1)+1,L,R);
	else
	{
	tmp=max(query(t<<1,L,mid),query((t<<1)+1,mid+1,R));//三者的最大值
	int tmp1=node[t<<1].right1>mid-L+1?mid-L+1:node[t<<1].right1;
	int tmp2=node[(t<<1)+1].left1>R-mid?R-mid:node[(t<<1)+1].left1;
	tmp=max(tmp,tmp1+tmp2);//合并后可能比单个大
	}
	return tmp;
}

int main()
{
	int op,L,R;
	while(scanf("%d",&n)!=EOF)
	{	
		;
		for(int i=1;i<=n;i++)
		scanf("%d",&a[i]);
		create(1,1,n);
		scanf("%d",&m);
		while(m--)
		{
			scanf("%d%d%d",&op,&L,&R);
			if(!op)cout<<query(1,L,R)<<endl;
			else update(1,L,R);
		}
	}
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值