线段树的典型应用之POJ 2823 Sliding Window解题报告

  题目出处:http://poj.org/problem?id=2823

  题目意思是说给出n个数,求k个相邻数的最大数和最小数。这个题看起来不难,可能会想到用暴力解决。但是由于数据规模较大,所以暴力绝对会超时。如果对线段树比较熟练的话就可以很容易看出来是考察线段树。我觉得可以这样思考:维护一颗含有k个元素的线段树,从j=0到n接受输入,把num[j]加入到树中。当j大于等于k时存储最大数和最小数的值,同时把num[j-k]这个元素从树中删除。这样全程仅需考虑树中的元素。不论是删除元素还是加入元素都必须维护树的性质没有改变。思路比较简单,只是线段树的实现比较繁琐。此处提供参考代码,给需要的同学一点启发:

#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
const int N = 1048576;
const int INF = 2000000000; 
vector<int> mv;
vector<int> nv;
struct Node{
	int max;
	int min;
}node[N << 1];
int num[N << 1];
void init()
{
	for (int i = 0; i < (N << 1); i++)
	{
		node[i].max = -INF;
		node[i].min = INF;
	}
}
inline int getleftchild(int p)
{
	return (p << 1);
}
inline int getrightchild(int p)
{
	return (p << 1) + 1;
}
inline int getparent(int c)
{
	return (c >> 1);
}
inline int getnode(int m)
{
	return N + m - 1;
}
void update(int p)
{
	int left = getleftchild(p);
	int right = getrightchild(p);
	node[p].min = min(node[left].min, node[right].min);
	node[p].max = max(node[left].max, node[right].max);
}
void add(int m)
{
	int cur = getnode(m);
	if (node[cur].min == INF)
	{
		node[cur].min = num[m];
		node[cur].max = num[m];
		do {
			cur = getparent(cur);
			update(cur);
		}while (cur > 1);
	}
}
void remove(int m)
{
	int cur = getnode(m);
	if (node[cur].min < INF)
	{
		node[cur].max = -INF;
		node[cur].min = INF;
		do{
			cur = getparent(cur);
			update(cur);
		}while (cur > 1);
	}
}
int main()
{
	int j;
	int a , b;
	vector<int>::iterator it;
	while (scanf("%d%d", &a, &b) == 2)
	{
		init();
		for (j = 0; j < a; j++)
		{
			scanf("%d", &num[j]);
			if (j >= b)
			{
				mv.push_back(node[1].max);
				nv.push_back(node[1].min);
				remove(j - b);
			}
		add(j);
		}
		mv.push_back(node[1].max);
		nv.push_back(node[1].min);
		for (it = nv.begin(); it != nv.end(); it++)
			printf("%d ", *it);
		printf("\n");
		for (it = mv.begin(); it != mv.end(); it++)
			printf("%d ", *it);
		printf("\n");
		mv.clear();
		nv.clear();
	}
	return 0;
}
posted @ 2011-02-13 13:05  like@neu  阅读(349)  评论(0编辑  收藏  举报