hdu 3911 Black And White 线段树区间合并

17 篇文章 0 订阅

题意就是开始给出n个黑白棋子,然后1.翻转连续的一段,即黑白颜色互换,2.查询连续一段区间里面连续的黑色棋子的最长长度。

hdu 1540是单点更新区间查询,这道是成段更新区间查询,两道的大致思路没什么区别,就是当前节点的maxlen为,当前节点控制范围里左最长连续和右最长连续,或者包括mid在内的一段连续(这里的连续指黑棋的连续区间)。但是不同的是这里还要记录白棋的信息,因为翻转的时候,正好翻转到某一颗子树控制的范围,那么只要去修改这颗子树的信息就好,而子树的信息记录了黑白两种信息的话,只需两种信息互换即可。总之简单区间合并的话还是按照这个套路来的。

#include <map>
#include <set>
#include <queue>
#include <stack>
#include <vector>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

#define lson l, mid, rt << 1
#define rson mid + 1, r, rt << 1 | 1
#define pi acos(-1.0)
#define eps 1e-8
typedef long long ll;
const int inf = 0x3f3f3f3f;

const int N = 100010;

struct node{
	int l, r;
	int l1, l0, r1, r0, max1, max0;
	int col, len;
}tr[N << 2];

int n, m;

int read()    
{    
    char ch=' ';    
    int ans=0;    
    while(ch<'0' || ch>'9')    
        ch=getchar();    
    while(ch<='9' && ch>='0')    
    {    
        ans=ans*10+ch-'0';    
        ch=getchar();    
    }    
    return ans;    
}   

void f( int rt )
{
	swap( tr[rt].l1, tr[rt].l0 );
	swap( tr[rt].r1, tr[rt].r0 );
	swap( tr[rt].max1, tr[rt].max0 );
	tr[rt].col ^= 1;
}

void pushup( int rt )
{
	tr[rt].l1 = tr[rt << 1].l1;
	if( tr[rt<<1].l1 == tr[rt<<1].len )
		tr[rt].l1 += tr[rt<<1|1].l1;
	
	tr[rt].l0 = tr[rt << 1].l0;
	if( tr[rt<<1].l0 == tr[rt<<1].len )
		tr[rt].l0 += tr[rt<<1|1].l0;
	
	tr[rt].r1 = tr[rt << 1 | 1].r1;
	if( tr[rt<<1|1].r1 == tr[rt<<1|1].len )
		tr[rt].r1 += tr[rt<<1].r1;	
	
	tr[rt].r0 = tr[rt << 1 | 1].r0;
	if( tr[rt<<1|1].r0 == tr[rt<<1|1].len )
		tr[rt].r0 += tr[rt<<1].r0;
	
	tr[rt].max1 = max( max(tr[rt<<1].max1, tr[rt<<1|1].max1), tr[rt<<1].r1 + tr[rt<<1|1].l1 );
	tr[rt].max0 = max( max(tr[rt<<1].max0, tr[rt<<1|1].max0), tr[rt<<1].r0 + tr[rt<<1|1].l0 );
}

void down( int rt )
{
	f( rt << 1 );
	f( rt << 1 | 1 );
	tr[rt].col = 0;
}

void build( int l, int r, int rt )
{
	tr[rt].l = l;
	tr[rt].r = r;
	tr[rt].len = r - l + 1;
	tr[rt].col = 0;
	if( l == r )
	{
		int x;
		scanf("%d", &x);
		if( x == 1 )
		{
			tr[rt].l1 = tr[rt].r1 = tr[rt].max1 = 1;
			tr[rt].l0 = tr[rt].r0 = tr[rt].max0 = 0;
		}
		else
		{
			tr[rt].l1 = tr[rt].r1 = tr[rt].max1 = 0;
			tr[rt].l0 = tr[rt].r0 = tr[rt].max0 = 1;
		}
		return;
	}
	int mid = ( l + r ) >> 1;
	build( lson );
	build( rson );
	pushup( rt );
}

void update( int l, int r, int rt )
{
	if( l <= tr[rt].l && tr[rt].r <= r )
	{
		f( rt );
		return;
	}
	if( tr[rt].col )
		down( rt );
	int mid = ( tr[rt].l + tr[rt].r ) >> 1;
	if( r <= mid )
		update( l, r, rt << 1 );
	else if( l > mid )
		update( l, r, rt << 1 | 1 );
	else
	{
		update( lson );
		update( rson );
	}
	pushup( rt );
}

int query( int l, int r, int rt )
{
	if( l <= tr[rt].l && tr[rt].r <= r )
		return tr[rt].max1;
	if( tr[rt].col )
		down( rt );
	int mid = ( tr[rt].l + tr[rt].r ) >> 1;
	int z, x, minn;
	if( r <= mid )
		return query( l, r, rt << 1 );
	else if( l > mid )
		return query( l, r, rt << 1 | 1 );
	else
	{
		z = query( lson );
		x = query( rson );
		minn = min( mid - l + 1, tr[rt<<1].r1 ) + min( r - mid, tr[rt<<1|1].l1 );
		return max( max( z, x ), minn );
	}
}

int main()
{
	while( ~scanf("%d", &n) )
	{
		build( 1, n, 1 );
		scanf("%d", &m);
		while( m -- )
		{
			int op, a, b;
			scanf("%d%d%d", &op, &a, &b);
			if( op == 1 )
				update( a, b, 1 );
			else
			{
				int ans = query( a, b, 1 );
				printf("%d\n", ans);
			}
		}
	}
	return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值