poj-2823

13 篇文章 0 订阅
// 24976K   6125MS  C++
#include <cstdio>
#include <cstring>

using namespace std;

#define K_MAX 1000010

#define INF 99999999

struct 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
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值