1. 程式人生 > >BZOJ 3314 [Usaco2013 Nov]Crowded Cows:單調隊列

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

problem href 遞增 感覺 spa lin efi sort n)

題目鏈接: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(); }

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