POJ 2823 Sliding Window 线段树区间求和问题
线段树区间求和问题,维护一个最大值一个最小值即可,线段树要用C++交才能过。
注意这道题不是求三个数的最大值最小值,是求k个的。
本题数据量较大,不能用N建树,用n建树。
还有一种做法是单调队列,耗时更少。
#include <iostream> #include <cstdio> #include <cmath> #include <cstring> #include <algorithm> #define N 1000005 using namespace std; int n,k; struct Tree { int l,r,mx,mn; }tree[N*4]; void build(int root,int l,int r) { tree[root].l=l; tree[root].r=r; if(l==r) { scanf("%d",&tree[root].mx); tree[root].mn=tree[root].mx; return; } int mid=(l+r)>>1; build(root<<1,l,mid); build(root<<1|1,mid+1,r); tree[root].mx=max(tree[root<<1].mx,tree[root<<1|1].mx); tree[root].mn=min(tree[root<<1].mn,tree[root<<1|1].mn); } int querymx(int root,int l,int r) { if(l<=tree[root].l&&r>=tree[root].r) return tree[root].mx; int mid=(tree[root].l+tree[root].r)>>1,ret=-1000000000; if(l<=mid) ret=max(querymx(root<<1,l,r),ret); if(r>mid) ret=max(querymx(root<<1|1,l,r),ret); return ret; } int querymn(int root,int l,int r) { if(l<=tree[root].l&&r>=tree[root].r) return tree[root].mn; int mid=(tree[root].l+tree[root].r)>>1,ret=1000000000; if(l<=mid) ret=min(querymn(root<<1,l,r),ret); if(r>mid) ret=min(querymn(root<<1|1,l,r),ret); return ret; } void pr() { for(int i=1;i<=n-k+1;i++) printf("%d ",querymn(1,i,i+k-1)); puts(""); for(int i=1;i<=n-k+1;i++) printf("%d ",querymx(1,i,i+k-1)); puts(""); } int main() { while(scanf("%d%d",&n,&k)!=EOF) { build(1,1,n); pr(); } return 0; }