【题目大意】
用若干个双端队列给$N$个整数排序,依次处理这$N$个数,对于每个数$A_i$,可以进行两种操作:
1.新建一个双端队列,并将$A_i$作为这个队列中唯一的数
2.把$A_i$从已有队列的队头或队尾入队
对所有的数处理完后,要求这些队列能够按照一定的顺序连接起来,得到一个非降的长度为$N$的序列,求最少需要多少个双端队列。
【思路分析】
我们把问题反过来思考,先把$N$个数从小到大排序,然后分成尽量少的几段,对应原问题中的合法双端队列。
易知一个结论,对于排序后每个位置的数原本的下标组成的序列$B$,如果一段满足单谷性质(即先递减后递增),那么这一段就对应原问题中的一个合法双端队列。(递减的一段相当于从队头插入,递增的一段相当于从队尾插入)
还要注意一点,就是如果存在相同的几个数,那么它们排序后的位置是随机的,可以看成一个整体来处理。如果这个整体中最小的下标大于前面的序列中最大的下标,那么满足递增;如果这个整体中最大的下标小于前面的序列中最小的下标,那么满足递减。
【代码实现】

1 #include<cstdio>
2 #include<iostream>
3 #include<cstring>
4 #include<algorithm>
5 #include<cmath>
6 #define g() getchar()
7 #define rg register
8 #define go(i,a,b) for(rg int i=a;i<=b;i++)
9 #define back(i,a,b) for(rg int i=a;i>=b;i--)
10 #define db double
11 #define ll long long
12 #define il inline
13 #define pf printf
14 using namespace std;
15 int fr(){
16 int w=0,q=1;
17 char ch=g();
18 while(ch<'0'||ch>'9'){
19 if(ch=='-') q=-1;
20 ch=g();
21 }
22 while(ch>='0'&&ch<='9') w=(w<<1)+(w<<3)+ch-'0',ch=g();
23 return w*q;
24 }
25 const int N=200002;
26 int n;
27 struct number{
28 int a,id;
29 }d[N];
30 struct line{
31 int minn,maxn;
32 }l[N];
33 il bool cmp(number x,number y){
34 return x.a<y.a;
35 }
36 int main(){
37 //freopen("","r",stdin);
38 //freopen("","w",stdout);
39 n=fr();
40 go(i,1,n) d[i].a=fr(),d[i].id=i;
41 sort(d+1,d+1+n,cmp);
42 rg int num=0;
43 go(i,1,n){//先处理一下相同的数字
44 l[++num].minn=d[i].id,l[num].maxn=d[i].id;
45 while(d[i].a==d[i+1].a){
46 i++;
47 l[num].minn=min(l[num].minn,d[i].id);
48 l[num].maxn=max(l[num].maxn,d[i].id);
49 }
50 }
51 bool now=0;rg int ans=1;
52 go(i,2,num){
53 if(now){//递增
54 if(l[i].minn>l[i-1].maxn) continue;
55 else ans++,now=0;
56 }
57 else{//递减
58 if(l[i].maxn<l[i-1].minn) continue;
59 else now=1;
60 }
61 }
62 pf("%d\n",ans);
63 return 0;
64 }
