bzoj2457: [BeiJing2011]双端队列

一开始见到这题还以为是水题(捂脸OZYFYC不要D我)瞎jb写了个set结果GG。。。

 

然后做法是这样的:首先一看就要排序,n=200000就是压线O(nlogn)啊,然后把每个数字的起始位置和结束位置求出来,那mn[x]~mx[x]就是范围,那可以发现,假如x<y,mx[x]<mn[y],那x和y就可以全放在一个双端队列里面,但是哪有那么好的事,肯定有x和y有相交的情况,那这种如何解决?因为我们开始排好了序,那贪心的时候就会从小到大,如果x<y,mn[y]<mx[x],那具体在原来的插入中就是x~y~x~y,而x往前延伸的先在前面做了,那我们就可以看作这一段就是y往后延伸。
数据的图:

具体的写法:首先先在原数列往前延伸,就是当前的数字,前面比自己大的,而且和自己没有交集的,那就可以不停的向前延伸,当遇到现在有交集的,那上面说过就交给他往后延伸,直到有交集,就只能新建一个双端队列。那为什么往后延伸和往前延伸这些数字不会冲突呢?因为往前延伸的数字(0)比停止往前延伸,开始往后延伸的数字(1)小,而往后延伸的数字比往后延伸的大,所以他们分别在双端队列的两边插入而互不影响。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std; 
struct node
{
    int x,id;
}a[210000];int len;
bool cmp(node n1,node n2)
{
    if(n1.x<n2.x||(n1.x==n2.x&&n1.id<=n2.id))return true;
    return false;
}
int mx[210000],mn[210000];
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i].x);  
        a[i].id=i;
    }
    sort(a+1,a+1+n,cmp);
    
    len=1;
    mn[len]=a[1].id;
    for(int i=2;i<=n;i++)
    {
        if(a[i-1].x!=a[i].x)
        {
            mx[len]=a[i-1].id;
            len++;
            mn[len]=a[i].id;
        }
    }
    
    int k=2147483647,ans=1;
    bool bk=false;
    for(int i=1;i<=len;i++)
    {  
        if(bk==false)
        {
            if(k>mx[i])k=mn[i];
            else 
            {
                k=mx[i];
                bk=true;
            }
        }  
        else if(bk==true)
        {
            if(k<mn[i])k=mx[i];
            else 
            {
                k=mn[i];
                bk=false;
                ans++;
            }
        }
    }
    printf("%d\n",ans);
    return 0;
}

 

posted @ 2017-10-09 17:18  AKCqhzdy  阅读(984)  评论(0编辑  收藏  举报