poj-2823

来源:互联网 发布:mysql时间转换成毫秒值 编辑:程序博客网 时间:2024/06/05 08:24
// 24976K   6125MS  C++#include <cstdio>#include <cstring>using namespace std;#define K_MAX 1000010#define INF 99999999struct TreeNode {    int left;    int right;    int max;    int min;};typedef struct TreeNode TreeNode;TreeNode tree[K_MAX<<2];int K;int replacePos;int ArrayLength;void buildTree(int pos, int begin, int end) {    tree[pos].left = begin;    tree[pos].right = end;    tree[pos].max = -INF;    tree[pos].min = INF;    // tree[pos].initialzed = 0;    if (begin == end) {        return;    } else {        int mid = (begin + end)>>1;        buildTree(pos<<1, begin, mid);        buildTree(pos<<1|1, mid+1, end);    }}void updateTreeNode(int pos) {    if (pos <= 0) { // reach top.        return;    } else {        int leftPos = pos<<1;        int rightPos = pos<<1|1;        TreeNode & leftNode = tree[leftPos];        TreeNode & rightNode = tree[rightPos];        tree[pos].max = leftNode.max > rightNode.max ?                        leftNode.max : rightNode.max;        tree[pos].min = leftNode.min < rightNode.min ?                        leftNode.min : rightNode.min;        updateTreeNode(pos>>1);    }}void insertTree(int pos, int replaceId, int newVal) {    int left = tree[pos].left;    int right = tree[pos].right;    if (left == right && left == replaceId) { // only one number in this range        tree[pos].max = newVal;        tree[pos].min = newVal;        // tree[pos].initialzed = 1;        updateTreeNode(pos>>1);// update parent node    } else {        int mid = (left + right)>>1;        if (replaceId <= mid) { // in left part            insertTree(pos<<1, replaceId, newVal);        } else { // in right part            insertTree(pos<<1|1, replaceId, newVal);        }    }}int array[K_MAX];int arrayKMin[K_MAX];int arrayKMax[K_MAX];int arrayKLength;int main() {    while(scanf("%d %d", &ArrayLength, &K) != EOF) {        buildTree(1, 1, K);        replacePos = 1;        arrayKLength = 0;        for (int i = 1; i <= ArrayLength; i++) {            scanf("%d", array + i -1);        }        for (int i = 1; i <= ArrayLength; i++) {            int val = array[i - 1];            // scanf("%d", &val);            if (i <= K) { // not fully-filled yet.                insertTree(1, i, val);                if (i == K) {                    arrayKMin[arrayKLength] = tree[1].min;                    arrayKMax[arrayKLength] = tree[1].max;                    arrayKLength++;                }            } else { // begin replace                insertTree(1, replacePos, val);                replacePos++;                if (replacePos >= K +1) {                    replacePos = 1;                }                arrayKMin[arrayKLength] = tree[1].min;                arrayKMax[arrayKLength] = tree[1].max;                arrayKLength++;                // printf("A %d %d\n", tree[1].min, tree[1].max);            }        }        for (int i = 1; i <= arrayKLength; i++) {            printf("%d ", arrayKMin[i - 1]);        }        printf("\n");        for (int i = 1; i <= arrayKLength; i++) {            printf("%d ", arrayKMax[i - 1]);        }        printf("\n");    }}

G++ TLE...  C++倒是过了。

貌似这道题最优解法是单调队列,不过用线段树也可以解出来,就用一把,

从应用角度看,是线段树的基础应用,并且可以体现线段树的优势:动态变化的数组,也可以很快得到答案。

不过这里面有一个小问题:那就是如何表示 window每次滑动带来的影响,因为每次滑动一个单位,就去掉一个数,引入一个新数,

线段树中,如果纯模拟线性数组的这种移动行为,就要对线段树的每个区间进行一次更新,绝对TLE,也体现不出线段树的优势,

一个办法就是维护一个变量R,保存这样一个值: 下一次滑动,要从数组中去掉的那个数的位置,然后将这个位置的数替换为新数即可,然后R++(下一个数就是下一次移动一应该去掉的数), 如果R>K, 那R 重置为 1

例子:

1 2 3 4 5 6 7

设窗口的长度为3, 那么初始就是 1 2 3,  R = 1

移动以后:  4 2 3, R =2

再次移动: 4 5 3,   R = 3

再次移动:  4 5 6, R = 1(重置为1)

这个过程就比较清晰解释了, 因为只需要求最大,最小,因为,对于窗口内部数的顺序是完全不care的,

所以每次滑动,只要能 去掉该去的数,加入新的数即可,

用这种办法,不需要更新线段树的每个区间,之需要更新R指定的单位区间即可,然后向上更新父区间的最大最小值即可,

一个值得记住的trick

0 0
原创粉丝点击