BZOJ 3314 [Usaco2013 Nov]Crowded Cows:单调队列

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3314

题意:

  N头牛在一个坐标轴上,每头牛有个高度。现给出一个距离值D。

  如果某头牛在它的左边,在距离D的范围内,如果找到某个牛的高度至少是它的两倍,且在右边也能找到这样的牛的话。则此牛会感觉到不舒服。

  问有多少头会感到不舒服。

题解:

  从左到右、从右到左两遍单调队列。

  单调性:

    (1)坐标x递增。

    (2)高度h递减。

  维护单调性:

    (1)从队首开始,所有与当前牛i的距离超过d的,以后都不会再用到。

    (2)从队尾开始,所有高度 <= 当前高度h[i]的,都不会再用到,因为当前牛i一定比前面的更优(又高又近)。

    (3)最后再将i压入队尾。

  每次判断一下之前最高的牛(队首)是不是h[i]的两倍,如果是则cnt[i]++。

  最后统计一下cnt[i] == 2的个数就好。

AC Code:

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#define MAX_N 50005

using namespace std;

struct Data
{
    int x;
    int h;
    Data(int _x,int _h)
    {
        x=_x;
        h=_h;
    }
    Data(){}
    friend bool operator < (const Data &a,const Data &b)
    {
        return a.x<b.x;
    }
};

int n,d;
int head;
int tail;
int ans=0;
int q[MAX_N];
int cnt[MAX_N];
Data dat[MAX_N];

void read()
{
    cin>>n>>d;
    for(int i=0;i<n;i++)
    {
        cin>>dat[i].x>>dat[i].h;
    }
}

void solve()
{
    sort(dat,dat+n);
    memset(cnt,0,sizeof(cnt));
    head=0;
    tail=0;
    for(int i=0;i<n;i++)
    {
        while(head<tail && dat[i].x-dat[q[head]].x>d) head++;
        while(head<tail && dat[q[tail-1]].h<=dat[i].h) tail--;
        if(head<tail && dat[q[head]].h>=dat[i].h*2) cnt[i]++;
        q[tail++]=i;
    }
    head=0;
    tail=0;
    for(int i=n-1;i>=0;i--)
    {
        while(head<tail && dat[q[head]].x-dat[i].x>d) head++;
        while(head<tail && dat[q[tail-1]].h<=dat[i].h) tail--;
        if(head<tail && dat[q[head]].h>=dat[i].h*2) cnt[i]++;
        q[tail++]=i;
    }
    for(int i=0;i<n;i++)
    {
        if(cnt[i]==2) ans++;
    }
}

void print()
{
    cout<<ans<<endl;
}

int main()
{
    read();
    solve();
    print();
}
原文地址:https://www.cnblogs.com/Leohh/p/7648857.html