POJ - 2823 滑动窗口

题目:

给一个长度为 NN 的数组,一个长为 KK 的滑动窗体从最左端移至最右端,你只能看到窗口中的 KK 个数,每次窗体向右移动一位。找出窗体在各个位置时的最大值和最小值。

思路:

网上好多人都是用的单调队列,这里给出一个用线段树的方法(如果没用O2优化甚至不一定能过,不好用hhh)。

可以将每一段的最大最小值记下来作为线段树的节点。

代码:

#include <bits/stdc++.h>
#define Pa pair< int, int >
#define MaxN 1000001
using namespace std;

typedef struct {
	int max, min;
	int left, right;
} node;
queue< Pa > que;
node tree[ MaxN << 2 ];
int line[ MaxN ];

void pushup( int po ) {
	tree[ po ].max = max( tree[ po << 1 ].max, tree[ po << 1 | 1 ].max );
	tree[ po ].min = min( tree[ po << 1 ].min, tree[ po << 1 | 1 ].min );
	return;
}

void bulitree( int po, int left, int right ) {
	if ( left == right ) {
		tree[ po ].left = left;
		tree[ po ].right = right;
		tree[ po ].min = line[ left ];
		tree[ po ].max = tree[ po ].min;
	} else {
		int mid = ( left + right ) >> 1;
		tree[ po ].left = left, tree[ po ].right = right;
		bulitree( po << 1, left, mid );
		bulitree( po << 1 | 1, mid + 1, right );
		pushup( po );
	}
}

Pa query( int po, int left, int right ) {
	if ( tree[ po ].left >= left && tree[ po ].right <= right ) {
		Pa p;
		p.first = tree[ po ].max, p.second = tree[ po ].min;
		return p;
	} else {
		Pa p, q;
		p.first = 0, p.second = 1000000001 ;
		int mid = ( tree[ po ].left + tree[ po ].right ) >> 1;
		if ( left <= mid ) {
			p = query( po << 1, left, right );
		}
		if ( right > mid ) {
			q = query( po << 1 | 1, left, right );
			p.first = max( p.first, q.first );
			p.second = min( p.second, q.second );
		}
		return p;
	}
}

int main( ) {
	int i, j, k;
	int N, K;
	scanf("%d %d", &N, &K );
	for ( i = 1; i <= N; i ++ ) {
		scanf("%d", &line[ i ] );
	}
	bulitree( 1, 1, N );
	for ( i = 1; i <= N - K + 1; i++ ) {
		que.push( query( 1, i, i + K - 1 ) );
		printf("%d ", que.back( ).second );
	}
	cout << endl;
	while ( !que.empty( ) ) {
		printf("%d ", que.front( ).first );
		que.pop( );
	}
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值