码迷,mamicode.com
首页 > 其他好文 > 详细

poj3667,线段树,区间合并,维护左,右,中区间

时间:2015-04-14 19:47:50      阅读:136      评论:0      收藏:0      [点我收藏+]

标签:

题目大意:Hotel有N(1 ≤ N ≤ 50,000)间rooms,并且所有的rooms都是连续排列在同一边,groups需要check in 房间,要求房间的编号为连续的r..r+Di-1并且r是最小的;visitors同样可能check out,并且他们每次check out都是编号为Xi ..Xi +Di-1 (1 ≤ Xi ≤ N-Di+1)的房间,题目的输入有两种样式:

  1. 1  a     :  groups需要check in  a间编号连续的房间,然后这些房间住进去
  2. 2  a   b : visitors  check out 房间,其中房间编号是 a…a+b-1,这些房间清空

要求对于每次request,输出为groups分配数目为a的房间中编号最小的房间编号


维护几个数据:该区间最大连续长度,从左边第一个开始的最大连续长度lmax,从右边开始的最大连续长度rmax,是否颜色一样(是某个颜色)tong;

然后a[root*2].rmax+a[root*2+1].lmax就是中间部分的长度,一些细节比较难以处理,要注意一下。

这题和POJ3368真的太像了,简直是孪生兄弟。

本题的重点是如何处理中间接起来的问题,当然3368也是。

具体就看代码吧:

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<math.h>
#include<stdlib.h>
using namespace std;
struct pai
{
	int left, right, lmax, rmax, zmax, tong,col;	
}a[50000*4+20];

struct PP
{
	int left; int right;
}o;
void up(int root)
{
	int tmax;
	if (a[root * 2].tong==1 && a[root * 2 + 1].tong==1)//说明房间还有,这里很可能有问题,脑子乱
	{
		a[root].tong = 1;
	}
	a[root].rmax = a[root * 2 + 1].rmax;
	a[root].lmax = a[root * 2].lmax;
	if (a[root * 2].rmax && a[root * 2 + 1].lmax)
	{
		if (a[root * 2 + 1].tong==1)
		{
			tmax = a[root * 2 + 1].zmax + a[root * 2].rmax;
			a[root].rmax = tmax;
		}
		if (a[root * 2].tong==1)
		{
			tmax = a[root * 2].zmax + a[root * 2 + 1].lmax;
			a[root].lmax = tmax;
		}
		tmax = a[root * 2].rmax + a[root * 2 + 1].lmax;
	}
	else
	{
		tmax = -1;
	}
	int max1 = a[root * 2].zmax;
	int max2 = a[root * 2 + 1].zmax;

	int max3 = max(max1, max2);
	max3 = max(tmax, max3);
	a[root].zmax = max3;
}
void down(int root)
{
	if (a[root].tong == 0)
	{
		a[root * 2].lmax =a[root*2].rmax=a[root*2].zmax= 0;
		a[root * 2+1].lmax = a[root * 2+1].rmax = a[root * 2+1].zmax = 0;
		a[root * 2].tong = a[root * 2 + 1].tong = 0;
		a[root].tong = 7;
	}
	if (a[root].tong == 1)
	{
		a[root * 2].lmax = a[root * 2].rmax = a[root * 2].zmax = a[root * 2].right - a[root * 2].left + 1;
		a[root * 2 + 1].lmax = a[root * 2 + 1].rmax = a[root * 2 + 1].zmax = a[root * 2+1].right - a[root * 2+1].left + 1;
		a[root * 2].tong = a[root * 2 + 1].tong = 1;
		a[root].tong = 7;
	}
}
void build(int left, int right, int root)
{
	a[root].left = left;
	a[root].right = right;
	if (left == right)
	{
		a[root].lmax = 1;
		a[root].rmax = 1;
		a[root].lmax = 1;
		a[root].zmax = 1;
		a[root].tong = 1;
		a[root].col = 1;
		return;
	}
	int m = (left + right) / 2;
	build(left, m, root * 2);
	build(m + 1, right, root * 2 + 1);
	up(root);
}

int search(int left, int right, int root,int x)
{
	if (a[root].zmax < x)
	{
		return -1;
	}
	if (a[root * 2].lmax >= x)
	{
		o.left = a[root * 2].left;
		o.right = a[root * 2].left + x - 1;
		return o.left;
	}
	if (a[root * 2].zmax >= x)
	{
		return search(a[root * 2].left, a[root * 2].right, root * 2, x);
	}
	if ((a[root * 2].rmax + a[root * 2 + 1].lmax) >= x)
	{
		o.left = a[root * 2].right - a[root * 2].rmax + 1;//这里有可能不对
		o.right = o.left + x - 1;
		return o.left;
	}

	return search(a[root * 2 + 1].left, a[root * 2 + 1].right, root * 2 + 1, x);
}


void change(int left, int right, int root, int x)
{
	if (a[root].left >= left && a[root].right <= right)
	{
		a[root].lmax = a[root].rmax = a[root].zmax=a[root].tong = 0;//tong先没搞
		return;
	}

	down(root);
	int m = (a[root].left + a[root].right) / 2;
	if (left <= m)
	{
		change(left, right, root * 2, x);
	}
	if (right > m)
	{
		change(left,right, root * 2+1, x);
	}
	up(root);

}

void change2(int left, int right, int root, int x)
{
	if (a[root].left >= left && a[root].right <= right)
	{
		a[root].lmax = a[root].rmax = a[root].zmax=a[root].right-a[root].left+1;
		a[root].tong = 1;
		return;
	}

	down(root);
	int m = (a[root].left + a[root].right) / 2;
	if (left <= m)
	{
		change2(left, right, root * 2, x);
	}
	if (right > m)
	{
		change2(left, right, root * 2 + 1, x);
	}
	up(root);
}
int main()
{
	int i,j,n, m,temp,b,c,temp2;
	while (~scanf("%d%d", &n, &m))
	{
		build(1, n, 1);
		for (i = 0; i < m; i++)
		{
			scanf("%d", &temp);

			if (temp == 1)
			{
				scanf("%d", &b);
				temp2=search(1, n, 1, b);
				if (temp2 != -1)
				{
					cout << temp2 << endl;
				}
				else
				{
					cout << '0' << endl;
					continue;
				}

				change(o.left, o.right, 1, 0);
			}
			else
			{
				scanf("%d%d", &b, &c);
				change2(b,b+c-1, 1, 1);
			}
		}







	}


}


poj3667,线段树,区间合并,维护左,右,中区间

标签:

原文地址:http://blog.csdn.net/nie8484/article/details/45045985

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!