线段树的典型应用之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;
}
浙公网安备 33010602011771号