poj 2201(RMQ+笛卡尔树)

给出一些结点

每个节点有两个关键字

要求构造一棵树

第一个关键字满足二叉搜索树的性质,第二个关键字满足小堆的性质


解题思路:这道题我开始是用第二关键字从小到大排序,然后从1-n去添加节点。这样是符合最小堆的性质,假设添加第i个节点,那么首先去找[1,i-1]这段区间的第一关键字的最小值和最大值,如果i节点的第一关键字大于最大值,就直接添加到最大值节点的右儿子,如果小于最小值,就添加到最小值节点的左儿子,否则就直接从根节点往下找。可是超时了,其实超时的原因还蛮明显的,因为你添加的i节点不一定每次都是大于最大值,小于最小值,更多的情况可能是在中间值,这样每次都要从根节点出发往下走,这样就会造成遍历的时间太多了。但按照这种思路,很难直接找到i节点的父节点是谁,因为[1,i-1]区间内的第一关键字是无序的。

参考了网上的思路,绝大部分都是按照第一关键字排序,然后再去找区间段内的最小值作为子树的根节点。

http://blog.csdn.net/sdj222555/article/details/7909198


我的TLE:

#include
#include
#include
#include
#include
using namespace std;

const int maxn = 50005;
struct Node
{
	int k,a;
	int id;

	bool operator < (const Node &T)
	{
		return a < T.a;
	}
}tree[maxn];
struct Result
{
	int parent,left,right;
}res[maxn];
int n,value[maxn],dp_max[maxn][20],dp_min[maxn][20];

int _max(int l,int r)
{
	if(tree[l].k > tree[r].k) return l;
	return r;
}

int _min(int l,int r)
{
	if(tree[l].k < tree[r].k) return l;
	return r;
}

void initRMQ()
{
	for(int i = 1; i <= n; i++)
		dp_max[i][0] = dp_min[i][0] = i;
	for(int j = 1; (1 << j) <= n; j++)
		for(int i = 1; i + (1 << j) - 1 <= n; i++)
		{
			dp_max[i][j] = _max(dp_max[i][j-1],dp_max[i+(1< tree[maxm].k)
		{
			res[tree[maxm].id].right = tree[i].id;
			res[tree[i].id].parent = tree[maxm].id;
		}
		else if(tree[i].k < tree[minm].k)
		{
			res[tree[minm].id].left = tree[i].id;
			res[tree[i].id].parent = tree[minm].id;
		}
		else
		{
			int p = tree[1].id;
			while(true)
			{
				if(tree[i].k > value[p])
				{
					if(res[p].right != 0)
						p = res[p].right;
					else
					{
						res[p].right = tree[i].id;
						res[tree[i].id].parent = p;
						break;
					}
				}
				else
				{
					if(res[p].left != 0)
						p = res[p].left;
					else
					{
						res[p].left = tree[i].id;
						res[tree[i].id].parent = p;
						break;
					}
				}
			}
		}
	}
}

int main()
{
	while(scanf("%d",&n)!=EOF)
	{
		for(int i = 1; i <= n; i++)
		{
			scanf("%d%d",&tree[i].k,&tree[i].a);
			tree[i].id = i;
			value[i] = tree[i].k;
		}
		sort(tree+1,tree+1+n);
		initRMQ();
		Build();
		printf("YES\n");
		for(int i = 1; i <= n; i++)
			printf("%d %d %d\n",res[i].parent,res[i].left,res[i].right);
	}
	return 0;
}


你可能感兴趣的:(RMQ)