poj 2823 Sliding Window 線段樹
Sliding Window
Time Limit: 12000MS
Memory Limit: 65536K
Total Submissions: 50906
Accepted: 14640
Case Time Limit: 5000MS
Description
An array of size n ≤ 106 is given to you. There is a sliding window of size k which is moving from the very left of the array to the very right. You can only see the k numbers in the window. Each time the sliding window moves rightwards by one position. Following is an example:
The array is [1 3 -1 -3 5 3 6 7], and k is 3.
Window position Minimum value Maximum value
[1 3 -1] -3 5 3 6 7 -1 3
1 [3 -1 -3] 5 3 6 7 -3 3
1 3 [-1 -3 5] 3 6 7 -3 5
1 3 -1 [-3 5 3] 6 7 -3 5
1 3 -1 -3 [5 3 6] 7 3 6
1 3 -1 -3 5 [3 6 7] 3 7
Your task is to determine the maximum and minimum values in the sliding window at each position.
Input
The input consists of two lines. The first line contains two integers n and k which are the lengths of the array and the sliding window. There are n integers in the second line.
Output
There are two lines in the output. The first line gives the minimum values in the window at each position, from left to right, respectively. The second line gives the maximum values.
Sample Input
8 3
1 3 -1 -3 5 3 6 7
Sample Output
-1 -3 -3 -3 3 3
3 3 5 5 6 7
題目大意:第一行輸入兩個數n,k,第二行輸入n個數。現在有一個長度為k的視窗,從第一個數開始滑動(每次滑動1個單位),每次只有視窗範圍中的數字可見。輸出兩行,第一行是每次視窗中的最小數,第二行是每次視窗中的最大數。
AC程式碼:
//用g++一直超時,要用c++,好坑
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
#define maxn 1000000
int num[maxn];
struct node
{
int minvalue, maxvalue; //此節點的值
int left,right; //此節點所維護區間的左右端點
}tree[maxn*4];
struct Node
{
int min, max;
}ans[maxn];
void build(int root,int left,int right)
{
tree[root].left = left;
tree[root].right = right;
if(left == right) //區間的左右端點相同,也就是到了葉子節點
{
tree[root].maxvalue = tree[root].minvalue = num[left];
return ;
}
int mid = (left+right) / 2;
build(root*2, left, mid); // 繼續構建左子樹
build(root*2+1, mid+1, right); //繼續構建右子樹
tree[root].maxvalue = max(tree[root*2].maxvalue,tree[root*2+1].maxvalue);
tree[root].minvalue = min(tree[root*2].minvalue,tree[root*2+1].minvalue);
}
//查詢left,right區間的最值 ,這裡用一個flag來標記查詢的是最大值還是最小值
int query(int root, int left, int right, int flag)
{
if(tree[root].left == left&&tree[root].right == right){
if(flag == 0)
return tree[root].minvalue;
if(flag == 1)
return tree[root].maxvalue;
}
if(right <= tree[2*root].right) //這個區間在根的左邊
return query(root*2, left, right, flag);
else if(left >= tree[root*2+1].left)//這個區間在根的右邊
return query(root*2+1, left, right, flag);
else //這個區間既在根的左邊又在根的右邊
{
int mid = (tree[root].left+tree[root].right) / 2;
if(flag == 0)
return min(query(root*2, left, mid, flag), query(root*2+1, mid+1, right, flag));
if(flag == 1)
return max(query(root*2, left, mid, flag), query(root*2+1, mid+1, right, flag));
}
}
int main()
{
int n, k;
while(scanf("%d %d",&n, &k) != EOF){
for(int i = 1; i <= n; i++)
scanf("%d", &num[i]);
build(1, 1, n);
for(int j = 1; j <= n-k+1; j++){
int right = j + k - 1;
ans[j].min = query(1, j,right ,0);
ans[j].max = query(1, j,right ,1);
}
for(int j = 1; j <= n-k+1; j++){
if(j == 1)
printf("%d", ans[j].min);
else
printf(" %d", ans[j].min);
}
printf("\n");
for(int j = 1; j <= n-k+1; j++){
if(j == 1)
printf("%d", ans[j].max);
else
printf(" %d", ans[j].max);
}
printf("\n");
}
return 0;
}