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; }
pain and happy in the cruel world.