zoukankan      html  css  js  c++  java
  • POJ 2823 Sliding Window (线段树/单调队列)

    题目不说了,可以用线段树或者单调队列,下面附上代码。

    线段树:

    #include <iostream>
    #include <stdio.h>
    #include <algorithm>
    /*
    AC
    线段树每个节点存储对应区间的最大值、最小值,然后直接查询即可。6594MS。
    */
    using namespace std;
    const int maxn=1000005;
    const int INF=0x3f3f3f3f;
    int minans[maxn],maxans[maxn];
    int small,bigger;
    int n,k;
    struct Node{
        int maxv,minv;
    }tree[maxn<<2];
    
    void pushUp(int rt){
        tree[rt].maxv=max(tree[rt<<1].maxv,tree[rt<<1|1].maxv);
        tree[rt].minv=min(tree[rt<<1].minv,tree[rt<<1|1].minv);
    }
    
    void build(int rt,int L,int R){
        if(L==R){
            scanf("%d",&tree[rt].minv);
            tree[rt].maxv=tree[rt].minv;
            return;
        }
        int mid=(L+R)>>1;
        build(rt<<1,L,mid);
        build(rt<<1|1,mid+1,R);
        pushUp(rt);
    }
    
    void query(int rt,int l,int r,int L,int R){
        if(l<=L && R<=r){
            small=min(small,tree[rt].minv);
            bigger=max(bigger,tree[rt].maxv);
            return;
        }
        int mid=(L+R)>>1;
        if(r<=mid)
            query(rt<<1,l,r,L,mid);
        else if(l>mid)
            query(rt<<1|1,l,r,mid+1,R);
        else{
            query(rt<<1,l,r,L,mid);
            query(rt<<1|1,l,r,mid+1,R);
        }
    }
    int main()
    {
        int idx=0;
        scanf("%d%d",&n,&k);
        build(1,1,n);
        for(int i=1;i<=n-k+1;i++){
            bigger=-INF;
            small=INF;
            query(1,i,i+k-1,1,n);
            minans[idx]=small;  //存储最小值序列
            maxans[idx]=bigger; //存储最大值序列
            idx++;
        }
        for(int i=0;i<idx;i++){
            if(i==0)
                printf("%d",minans[i]);
            else
                printf(" %d",minans[i]);
        }
        printf("
    ");
        for(int i=0;i<idx;i++){
            if(i==0)
                printf("%d",maxans[i]);
            else
                printf(" %d",maxans[i]);
        }
        printf("
    ");
        return 0;
    }

    单调队列:

    #include <iostream>
    #include <stdio.h>
    /*
    AC 5204ms
    利用单调队列,分两次处理,第一次求最小值序列,第二次求最大值序列。
    
    以求最小值序列为例:
    先处理前k-1个元素,每次从队尾加入队列之前,先与队尾元素比较,若比队尾元素值小,则删去队尾元素,直到有比它小的,或者队列为空,
    将该元素插入到队尾。即每次保证队列为单调非减队列,队首元素始终是队列中最小的。
    
    接下来依次读入一个元素,与队尾元素比较,若队尾元素大,则删去队尾元素,直至遇到比要插入的元素小或者队列为空为止,插入该元素。
    由于要求的是连续的k个区间,所以还要把队列中在该区间之前的元素删去。
    这里有个技巧,也就是队列中,存储的不是元素值,而是在数组中的位置,这样很容易判断某个元素是否在连续的k个区间内,
    获取元素值的话,就通过存储的数组下标获取。
    
    求最大值序列的时候,同最小值序列,保证队列为非增队列,即队列的首个元素一定是最大的。
    
    */
    using namespace std;
    const int maxn=1000005;
    int n,k;
    int a[maxn]; //n个元素值
    int dequeue[maxn]; //单调队列
    //求最小值序列
    void minans(int k,int n) {
        int head=1;
        int tail=0;
        //先处理前k-1个元素
        for(int i=0; i<k-1; i++) {
            while(head<=tail  &&  a[dequeue[tail]]>=a[i]) {
                tail--;
            }
            tail++;
            dequeue[tail]=i;  //存储的是元素在a中的索引
        }
        for(int i=k-1; i<n; i++) {
            while(head<=tail  && a[dequeue[tail]]>=a[i]) {
                tail--;
            }
            tail++;
            dequeue[tail]=i;
            while(dequeue[head]<i-k+1)  //将索引在i-k+1之前的元素删去
                head++;
            printf("%d ",a[dequeue[head]]);  //输出队列首个元素,即最小的元素
    
        }
    }
    //求最大值序列
    void maxans(int k,int n) {
        int head=1;
        int tail=0;
        for(int i=0; i<k-1; i++) {
            while(head<=tail  &&  a[dequeue[tail]]<=a[i]) {
                tail--;
            }
            tail++;
            dequeue[tail]=i;
        }
        for(int i=k-1; i<n; i++) {
            while(head<=tail  && a[dequeue[tail]]<=a[i]) {
                tail--;
            }
            tail++;
            dequeue[tail]=i;
            while(dequeue[head]<i-k+1)
                head++;
            printf("%d ",a[dequeue[head]]);
    
    
        }
    }
    
    int main() {
        scanf("%d%d",&n,&k);
        for(int i=0; i<n; i++) {
            scanf("%d",&a[i]);
        }
        minans(k,n);
        printf("
    ");
        maxans(k,n);
        //printf("
    ");
        return 0;
    }
  • 相关阅读:
    P2494 [SDOI2011]保密 最小割
    P2765 魔术球问题
    [CTSC2008]祭祀river
    CF311E Biologist
    P4177 [CEOI2008]order
    函数的形参和实参
    python字符编码
    源码安装Vim并配置YCM自动补全插件
    Python基础练习之购物车
    Python字符串的所有操作
  • 原文地址:https://www.cnblogs.com/chenxiwenruo/p/3395397.html
Copyright © 2011-2022 走看看