首页 > 代码库 > HDU 3911 Black And White 分段树 题解

HDU 3911 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

分段树依旧是难题,本题能够说是分段树的基本操作,可是由于情况好多,程序好长,所以十分耗时间。

之所以使用线段树,不使用一般的动态规划法,是要把每次查询的时间效率降到 (Lgn)。

分段,每段都要维护8个数据,所以非常繁琐。

做的好累,代码改动了非常多次,终于代码算比較清晰的了。有分段树思想的人应该都不难follow。

Hdu是不同意使用free释放空间的,否则出错,奇怪的OJ。

#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <algorithm>
#include <math.h>
using namespace std;

class BlackAndWhite3911
{
	int arrSize, tSize;
	int *arr;
	struct Node
	{
		int le0, le1, ri0, ri1;
		int len0, len1;
		int totalLen;
		bool lazy;
	};

	Node *SegTree;
	void updateNode(int r, int L, int R)
	{
		if (SegTree[L].le0 == SegTree[L].totalLen)
			SegTree[r].le0 = SegTree[L].le0 + SegTree[R].le0;
		else	SegTree[r].le0 = SegTree[L].le0;

		if (SegTree[R].ri0 == SegTree[R].totalLen)
			SegTree[r].ri0 = SegTree[L].ri0 + SegTree[R].ri0;
		else SegTree[r].ri0 = SegTree[R].ri0;

		if (SegTree[L].le1 == SegTree[L].totalLen)
			SegTree[r].le1 = SegTree[L].le1 + SegTree[R].le1;
		else SegTree[r].le1 = SegTree[L].le1;

		if (SegTree[R].ri1 == SegTree[R].totalLen)
			SegTree[r].ri1 = SegTree[L].ri1 + SegTree[R].ri1;
		else SegTree[r].ri1 = SegTree[R].ri1;

		int a = max(SegTree[L].len0, SegTree[R].len0);
		int b = SegTree[L].ri0 + SegTree[R].le0;
		SegTree[r].len0 = max(a, b);

		a = max(SegTree[L].len1, SegTree[R].len1);
		b = SegTree[L].ri1 + SegTree[R].le1;
		SegTree[r].len1 = max(a, b);		
	}

	void conHelper(int low, int up, int r = 0)
	{
		if (low == up)
		{
			if (0 == arr[low])
			{
				SegTree[r].len0 = 1, SegTree[r].len1 = 0;
				SegTree[r].le0 = 1, SegTree[r].ri0 = 1;
				SegTree[r].le1 = 0, SegTree[r].ri1 = 0;
			}
			else
			{
				SegTree[r].len0 = 0, SegTree[r].len1 = 1;
				SegTree[r].le0 = 0, SegTree[r].ri0 = 0;
				SegTree[r].le1 = 1, SegTree[r].ri1 = 1;
			}
			SegTree[r].lazy = false;
			SegTree[r].totalLen = 1;
			return ;
		}

		int mid = low + ((up-low)>>1);
		int le = (r<<1) + 1;
		int ri = (r<<1) + 2;

		conHelper(low, mid, le);
		conHelper(mid+1, up, ri);

		SegTree[r].totalLen = up - low + 1;
		updateNode(r, le, ri);
		SegTree[r].lazy = false;
	}

	void conTree()
	{
		int h = (int) ceil(log((double)arrSize)/log(2.0)) + 1;
		tSize = (int) pow(2.0, h) - 1;
		SegTree = (Node *) malloc(sizeof(Node) * tSize);
		conHelper(0, arrSize-1);
	}

	void accessNode(int r)
	{
		SegTree[r].lazy = !SegTree[r].lazy;
		swap(SegTree[r].le0, SegTree[r].le1);
		swap(SegTree[r].ri0, SegTree[r].ri1);
		swap(SegTree[r].len0, SegTree[r].len1);
	}

	void segUpdate(const int low, const int up, int L, int R, int r = 0)
	{
		if (low == L && R == up)
		{
			accessNode(r);
			return;
		}

		int le = (r<<1) + 1;
		int ri = (r<<1) + 2;

		if (SegTree[r].lazy)
		{
			SegTree[r].lazy = false;
			if (le < tSize) accessNode(le);
			if (ri < tSize) accessNode(ri);
		}

		int M = L + ((R-L)>>1);

		if (up <= M) segUpdate(low, up, L, M, le);
		else if (low > M) segUpdate(low, up, M+1, R, ri);
		else
		{
			segUpdate(low, M, L, M, le);
			segUpdate(M+1, up, M+1, R, ri);
		}
		updateNode(r, le, ri);
	}

	int getLongest(const int low, const int up, int L, int R, int r = 0)
	{
		if (low == L && R == up)//不能low <= L && R <= up
		{
			return SegTree[r].len1;
		}

		int le = (r<<1) + 1;
		int ri = (r<<1) + 2;
		if (SegTree[r].lazy) 
		{
			SegTree[r].lazy = false;
			if (le < tSize) accessNode(le);
			if (ri < tSize) accessNode(ri);
		}

		int M = L + ((R-L)>>1);

		//在任一边子树
		if (up <= M) return getLongest(low, up, L, M, le);
		if (low > M) return getLongest(low, up, M+1, R, ri);

		//跨左右子树的情况
		int llen = getLongest(low, M, L, M, le);//(low, up, L, M, le);
		int rlen = getLongest(M+1, up, M+1, R, ri);//(low, up, M+1, R, ri);

		int a = min(M-low+1, SegTree[le].ri1);
		int b = min(up-M, SegTree[ri].le1);
		int c = a + b;

		return max(c, max(llen, rlen));
	}
public:
	BlackAndWhite3911()
	{
		int N;
		while ( (scanf("%d", &N) != EOF))
		{
			arrSize = N;
			arr = (int *)malloc(sizeof(int) * arrSize);

			for (int i = 0; i < N; i++)
			{
				scanf("%d", &arr[i]);
			}

			conTree();

			int T;
			scanf("%d", &T);
			int a, b, c;
			while (T--)
			{
				scanf("%d %d %d", &a, &b, &c);
				if (0 == a)
					printf("%d\n",getLongest(b-1, c-1, 0, arrSize-1));
				else segUpdate(b-1, c-1, 0, arrSize-1);	
			}
		}
	}

	~BlackAndWhite3911()
	{
		if (arr) free(arr);
		if (SegTree) free(SegTree);
	}
};