线段树的典型应用之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; }