POJ2528 海报问题(线段树+离散化)

有一两年没有搞了,有点生疏,这道题目是线段树的,以前在学校搞过,

搞这道题目第二天才搞出来,而且参考了另外的解题报告。

http://blog.csdn.net/lyy289065406/article/details/6799170

问题的抽象如下,

// 给定一条数轴,长度为 L<=1千万单位,然后在数轴上的某些区间染色,第i次对区间染色为i,共染色N<=10000次。给出每次染色的区间,问最后能看见多少种颜色。


// 线段树处理染色问题,离散化处理,数据压缩
// 创建线段树和搜索线段采用递归方式
// 利用完全二叉树,N个点的层数为 logN + 1 
// 2W个点,层数为16,对应的树节点个数为 2^16 = 64 * 1024 = 65536


// 用递归创建二叉树要比用队列快的多,
// 范围 1, 20000 创建10次 createSegTree_re 运行速度是 15 ms
// 范围 1, 20000 创建10次 createSegTree 运行速度是 782 ms


// 哈哈,poj过了,一步一步改为用递归方法,终于没有超时,过了。。。。
// 2792K 469MS C++ 5032B 2013-11-27 15:57:30
// 2792K 485MS C++ 4401B 2013-11-27 16:02:47
// 2792K 422MS C++ 4461B 2013-11-27 16:06:30


整个代码如下:(采用递归方式)

#include<iostream>
#include<vector>
#include<map>
#include <string>
#include <set>
#include <stack>
#include <queue>
using namespace std;

#include <stdio.h>
#include <string.h>
//#include "mysys.h"
//#include <Windows.h>


struct segTreeNode
{
	int iID;
	int iLeft;
	int iRight;
	
	int iInfo;

	segTreeNode():iID(-1){iInfo = 0;iLeft = -1;iRight = -1;};
};


segTreeNode g_SegTree[100000] = {};
bool g_SegFlag[10001] = {};

int createSegTree_re(int iCen, int iLeft, int iRight) // 递归创建完全二叉树
{
	g_SegTree[iCen].iID = iCen;
	g_SegTree[iCen].iLeft = iLeft;
	g_SegTree[iCen].iRight = iRight;
	g_SegTree[iCen].iInfo = 0;

	if(iLeft == iRight)
	{
		return 1;
	}

	int iMid = (iLeft + iRight) / 2;
	createSegTree_re(iCen*2, iLeft, iMid);
	createSegTree_re(iCen*2 + 1, iMid+1, iRight);

	return 0;
}

void throughSegTree_re(int iInLeft, int iInRight, int iInfo, int iCen)
{
	if(iInRight < g_SegTree[iCen].iLeft || iInLeft > g_SegTree[iCen].iRight) // 没有交集
	{
		return ;
	}

	if(iInLeft <= g_SegTree[iCen].iLeft && iInRight >= g_SegTree[iCen].iRight)
	{
		g_SegTree[iCen].iInfo = iInfo;
		return ;
	}
	
	if(0 != g_SegTree[iCen].iInfo) // 当前节点有颜色,传递给孩子
	{
		g_SegTree[iCen * 2 + 1].iInfo = g_SegTree[iCen].iInfo; // 颜色传给右孩子
		g_SegTree[iCen * 2].iInfo = g_SegTree[iCen].iInfo; // 颜色传给左孩子

		g_SegTree[iCen].iInfo = 0; // 自己颜色清空
	}

	throughSegTree_re(iInLeft, iInRight, iInfo, iCen * 2);
	throughSegTree_re(iInLeft, iInRight, iInfo, iCen * 2 + 1);

	return ;
}

int g_iNum = 0;

void dfsInfo(int iCen)
{
	if(0 != g_SegTree[iCen].iInfo)
	{
		if(!g_SegFlag[g_SegTree[iCen].iInfo])
		{
			g_SegFlag[g_SegTree[iCen].iInfo] = true;
			g_iNum++;
		}

		return ;
	}
	
	if(g_SegTree[iCen].iLeft != g_SegTree[iCen].iRight)
	{
		dfsInfo(iCen*2);
		dfsInfo(iCen*2 + 1);
	}
}

void clear()
{
	memset(g_SegFlag,0,sizeof(g_SegFlag) / sizeof(g_SegFlag[0]));  	

	g_iNum = 0;
}

int main()
{

	int iNumTest = 0;
	int iNumSeg = 0;
	int iLeft = 0;
	int iRight = 0;
	
	int iTreeLeft = 0;
	int iTreeRight = 0;

	map<int, int>  mapTemp;
	map<int, int>::iterator it;
	vector<pair<int, int> >  vctPair;
	vector<pair<int, int> >::iterator itvct;

	scanf("%d",&iNumTest);

	for(int i = 0; i < iNumTest; i++)
	{
		mapTemp.clear();
		vctPair.clear();

		scanf("%d",&iNumSeg);
		
		for(int j = 0; j < iNumSeg; j++)
		{
			scanf("%d %d", &iLeft, &iRight);

			if(mapTemp.end() == mapTemp.find(iLeft))
			{
				mapTemp.insert(make_pair(iLeft, 0));
			}

			if(mapTemp.end() == mapTemp.find(iRight))
			{
				mapTemp.insert(make_pair(iRight, 0));
			}

			vctPair.push_back(make_pair(iLeft, iRight));
		}

		int iTempIndex = 1;
		for(it = mapTemp.begin(); it != mapTemp.end(); it++)
		{
			it->second = iTempIndex;

			iTempIndex = iTempIndex + 1;
		}

		for(itvct = vctPair.begin(); itvct != vctPair.end(); itvct++)
		{
			itvct->first = mapTemp[itvct->first];
			itvct->second = mapTemp[itvct->second];
		}

		iTreeLeft = 1;
		iTreeRight = iTempIndex-1;
		
		//createSegTree(iTreeLeft, iTreeRight);

		clear();
		createSegTree_re(1, iTreeLeft, iTreeRight);

		int iFlag = 1;
		for(itvct = vctPair.begin(); itvct != vctPair.end(); itvct++)
		{
			//throughSegTree(itvct->first, itvct->second, iFlag++);
			throughSegTree_re(itvct->first, itvct->second, iFlag++, 1);
		}
		
		dfsInfo(1);

		printf("%d\n", g_iNum);
	}
	
	
	return 0;
}


整个代码如下:(采用栈和队列方式,总是超时)

#include<iostream>
#include<vector>
#include<map>
#include <string>
#include <set>
#include <stack>
#include <queue>
using namespace std;

#include <stdio.h>
//#include "mysys.h"
//#include <Windows.h>


struct segTreeNode
{
	int iID;
	int iLeft;
	int iRight;
	
	int iInfo;

	segTreeNode():iID(-1){iInfo = 0;iLeft = -1;iRight = -1;};
};

struct qdata
{
	int i;
	int iL;
	int iR;

	qdata(int _in_i = -1, int _in_iL = -1, int _in_iR = -1):i(_in_i), iL(_in_iL), iR(_in_iR)
	{

	};
};

segTreeNode g_SegTree[200000] = {};

int createSegTree(int iLeft, int iRight) // 利用队列广度搜索创建完全二叉树
{
	int iMid = 0;
	qdata aData;
	queue<qdata> que;
	que.push(qdata(1, iLeft, iRight));

	while(!que.empty())
	{
		aData = que.front();
		que.pop();

		g_SegTree[aData.i].iID = aData.i;
		g_SegTree[aData.i].iLeft = aData.iL;
		g_SegTree[aData.i].iRight = aData.iR;
		g_SegTree[aData.i].iInfo = 0;

		if(aData.iL == aData.iR)
		{
			continue;
		}
		
		iMid = (aData.iR + aData.iL) / 2;
		que.push(qdata(aData.i*2, aData.iL, iMid));
		que.push(qdata(aData.i*2 + 1, iMid+1, aData.iR));

	}

	return 0;
}

int throughSegTree(int iInLeft, int iInRight, int iInfo)
{
	if(iInLeft > iInRight)
	{
		return 1;
	}

	stack<int>  stNode;
	
	if(iInLeft >= g_SegTree[1].iLeft && iInRight <= g_SegTree[1].iRight)
	{
		stNode.push(1);
	}
	
	int iTop = 0;
	int iMid = 0;
	int iTLeft = 0;
	int iTRight = 0;

	while(!stNode.empty()) // 深度优先搜索
	{
		iTop = stNode.top();
		stNode.pop();
//cout<<iInLeft<<" "<<iInRight<<" "<<iTop<<" "<<stNode.size()<<endl;
		iTLeft = iInLeft;
		if(iInLeft < g_SegTree[iTop].iLeft)
		{
			iTLeft = g_SegTree[iTop].iLeft;
		}
		
		iTRight = iInRight;
		if(iInRight > g_SegTree[iTop].iRight)
		{
			iTRight = g_SegTree[iTop].iRight;
		}
		
		if(iTLeft == g_SegTree[iTop].iLeft && iTRight == g_SegTree[iTop].iRight)
		{
			g_SegTree[iTop].iInfo = iInfo;
			continue;
		}

		iMid = (g_SegTree[iTop].iLeft + g_SegTree[iTop].iRight) / 2;

		if(iTRight <= iMid)
		{
			stNode.push(iTop * 2);

			if(0 != g_SegTree[iTop].iInfo) // 要有颜色才能往下传
			{
				g_SegTree[iTop * 2 + 1].iInfo = g_SegTree[iTop].iInfo; // 颜色传给右孩子
			}
		}
		else if(iTLeft > iMid)
		{
			stNode.push(iTop * 2 + 1);

			if(0 != g_SegTree[iTop].iInfo)
			{
				g_SegTree[iTop * 2].iInfo = g_SegTree[iTop].iInfo; // 颜色传给左孩子
			}
		}
		else
		{
			stNode.push(iTop * 2 + 1);
			stNode.push(iTop * 2);

			if(0 != g_SegTree[iTop].iInfo)
			{
				g_SegTree[iTop * 2 + 1].iInfo = g_SegTree[iTop].iInfo; // 颜色传给右孩子
				g_SegTree[iTop * 2].iInfo = g_SegTree[iTop].iInfo; // 颜色传给左孩子
			}
		}

		g_SegTree[iTop].iInfo = 0; // 自己颜色清空
	}

	return 0;
}

int main()
{
	int iNumTest = 0;
	int iNumSeg = 0;
	int iLeft = 0;
	int iRight = 0;
	
	int iTreeLeft = 0;
	int iTreeRight = 0;

	map<int, int>  mapTemp;
	map<int, int>::iterator it;
	set<int> setTemp;
	vector<pair<int, int> >  vctPair;
	vector<pair<int, int> >::iterator itvct;

	scanf("%d",&iNumTest);

	for(int i = 0; i < iNumTest; i++)
	{
		mapTemp.clear();
		vctPair.clear();
		setTemp.clear();

		scanf("%d",&iNumSeg);
		
		for(int j = 0; j < iNumSeg; j++)
		{
			scanf("%d %d", &iLeft, &iRight);

			if(mapTemp.end() == mapTemp.find(iLeft))
			{
				mapTemp.insert(make_pair(iLeft, 0));
			}

			if(mapTemp.end() == mapTemp.find(iRight))
			{
				mapTemp.insert(make_pair(iRight, 0));
			}

			vctPair.push_back(make_pair(iLeft, iRight));
		}

		int iTempIndex = 1;
		for(it = mapTemp.begin(); it != mapTemp.end(); it++)
		{
			it->second = iTempIndex;

			iTempIndex = iTempIndex + 1;
		}

		for(itvct = vctPair.begin(); itvct != vctPair.end(); itvct++)
		{
			itvct->first = mapTemp[itvct->first];
			itvct->second = mapTemp[itvct->second];
		}

		iTreeLeft = 1;
		iTreeRight = iTempIndex+1;
		
		createSegTree(iTreeLeft, iTreeRight);

		int iFlag = 1;
		for(itvct = vctPair.begin(); itvct != vctPair.end(); itvct++)
		{
			throughSegTree(itvct->first, itvct->second, iFlag++);
		}
		
		queue<int>  que;
		int iFront = 0;
		
		if(0 == g_SegTree[1].iInfo)
		{
			que.push(1);
		}
		else
		{
			setTemp.insert(1);
		}
		
		while(!que.empty())  // 广度优先搜索
		{
			iFront = que.front();
			que.pop();

			if(0 == g_SegTree[iFront].iInfo)
			{
				if(g_SegTree[iFront].iLeft != g_SegTree[iFront].iRight)
				{
					que.push(iFront * 2);
					que.push(iFront * 2 + 1);
				}
			}
			else
			{
				setTemp.insert(g_SegTree[iFront].iInfo);
			}
		}

		printf("%d\n", setTemp.size());

	}
	
	return 0;
}





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值