BZOJ 3314 [Usaco2013 Nov]Crowded Cows:單調佇列

Leohh發表於2017-10-11

題目連結: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();
}

 

相關文章