// 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