ACM -- 单调队列

今天总结一下单调队列;
单调队列,顾名思义,这个队列必须是单调的,要么单调增要么单调减,可以说单调队列就是一个维护数据单调性的一种数据结构;

假设有一个单调递增的队列1,2,3,5。如果加入一个大于5的元素,就可以直接追加到末尾,这样不会破坏队列的单调性,如果加入一个元素4,那么为了维护队列的单调性就要先将5出队,然后将4入队后再将5入队,从而维护队列的单调性。因此引入了一种新队列——双端队列

单调队列可以处理的问题:
1、可以查询区间最值(不能维护区间k大,因为队列中很有可能没有k个元素)
2、优化DP。单调队列一般是用于优化动态规划方面问题的一种特殊数据结构,且多数情况是与定长连续子区间问题相关联。

下面看一个单调队列的一个例题;

题目描述

某地有 N 个能量发射站排成一行,每个发射站 i 都有不相同的高度 Hi,并能向两边(当 然两端的只能向一边)同时发射能量值为 Vi 的能量,并且发出的能量只被两边最近的且比 它高的发射站接收。

显然,每个发射站发来的能量有可能被 0 或 1 或 2 个其他发射站所接受,特别是为了安 全,每个发射站接收到的能量总和是我们很关心的问题。由于数据很多,现只需要你帮忙计 算出接收最多能量的发射站接收的能量是多少。

输入输出格式
输入格式:

第 1 行:一个整数 N;

第 2 到 N+1 行:第 i+1 行有两个整数 Hi 和 Vi,表示第 i 个人发射站的高度和发射的能量值。

输出格式:

输出仅一行,表示接收最多能量的发射站接收到的能量值,答案不超过 longint。

下面是解题代码,可以仔细理解一下:

#include
#include
#include
#include
#include
using namespace std;
struct node{
	int x,dfn;
}team[1000001];
struct sz{
    int h,v;
}a[1000001];
long long n,m,tail,head;
long long i,j,b[1000001];
long long ans[1000001],maxn;
inline int read(){
    int x=0,f=1;
    char ch=getchar();
    while(ch>'9'||ch<'0'){ if(ch=='-') f=-1; ch=getchar();}
    while(ch<='9' && ch>='0'){x=x*10+ch-'0'; ch=getchar();}
    return x*f;
}
void write(long long x){
    if(x<10){putchar(x%10+48); return;}
    write(x/10); putchar(x%10+48); 
}
int main(){
    n=read();
    for (i=1; i<=n; i++) 
        a[i].h=read(),a[i].v=read();
    head=1; tail=1;
    team[head].x=a[n].h; team[head].dfn=n;
	b[n]=0;
    for (i=n-1; i>=1; i--){
        while (head<=tail&&a[i].h>=team[tail].x) tail--;
        tail++;
        team[tail].x=a[i].h; team[tail].dfn=i;
        if (team[head].x<=a[i].h) b[i]=0;
        else{
            b[i]=team[tail-1].dfn;
            ans[b[i]]+=a[i].v;
        }
    }
    head=1; tail=1;
    team[head].x=a[1].h; team[head].dfn=1;
    b[n]=0;
    for (i=2; i<=n; i++){
        while (head<=tail&&a[i].h>=team[tail].x) tail--;
        tail++;
        team[tail].x=a[i].h; team[tail].dfn=i;
        if (team[head].x<=a[i].h) b[i]=0;
        else{
            b[i]=team[tail-1].dfn;
            ans[b[i]]+=a[i].v;
        }
    }
    for (i=1; i<=n; i++)
        if (ans[i]>maxn) maxn=ans[i];
    write(maxn);
    return 0;
}

你可能感兴趣的:(ACM,C++,算法)