前言
考场题看错了
看错版本
题面
给你若干个区间,选择尽可能多的区间,使得在这些区间内,每一个区间存在一个数,这一些数单调不降。
sol
用一个简单的dp就行了。
离散化后dp[i]表示以选择i结尾的最多的选择的区间数量。
显然,设当前枚举到的为
[l,r]
[
l
,
r
]
有
1.
dp[l]=maxi<li=1(dp[l],dp[i]+1)
d
p
[
l
]
=
m
a
x
i
=
1
i
<
l
(
d
p
[
l
]
,
d
p
[
i
]
+
1
)
。
2.
dp[i](i∈[l,r])=dp[i](i∈[l,r])+1
d
p
[
i
]
(
i
∈
[
l
,
r
]
)
=
d
p
[
i
]
(
i
∈
[
l
,
r
]
)
+
1
这样就是dp方程,发现显然可以用线段树,对于
[1,l)
[
1
,
l
)
的进行最大值询问,对于
[l,r]
[
l
,
r
]
的进行区间加法
复杂度
O(nlogn)
O
(
n
l
o
g
n
)
正确版本
题面
戳
给你若干个区间,选择尽可能多的连续区间,使得在这些区间内,每一个区间存在一个数,这一些数单调不降。(注意连续这两个字)
sol
这就肯定维护一个单调队列,能加就加。
加不了了,就要从第一个开始弹。
但是弹到什么时候,谁也不知道。但是可以记录下最大值,也就是最大的左端点,因为是最大的左端点卡住了,使得你无法加入新的元素,所以你只需要关注最大的,然后把它弹掉,弹掉最大的,接下来是否需要继续弹,就看接下来的最大值。接下来的最大值一定比刚才弹掉的小,笔接下来的最大值大。这个时候就用一个东西装一下这些越来越小的最大值,这用一个单调队列就可以了。具体看代码
code
#include<bits/stdc++.h>
using namespace std;
inline char gc(){
static char buf[1<<7],*p1=buf,*p2=buf;
return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,1<<7,stdin),p1==p2)?EOF:*p1++;
}
template <class T>
inline void read(T&data){
data=0;
register int caa=1;
register char ch=0;
while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
ch=='-'?caa=-1,ch=getchar():caa=1;
while(ch<='9'&&ch>='0'){
data=(data<<3)+(data<<1)+(ch^48);
ch=getchar();
}
data*=caa;return;
}
const int _ =1e6+6;
int n;
int l[_],r[_],stk[_],head,wei,q[_],head1,wei1;
int main(){
read(n);head=1,head1=1;
register int Ans=0,ans=0,L=1,R=1;
for(;R<=n;++R)
{
read(l[R]),read(r[R]);
if(r[R]<stk[head][l] && head<=wei){
Ans=max(Ans,R-L);
while(stk[head][l]>r[R] && head<=wei)L = stk[head]+1,++head;
}
while(stk[wei][l]<l[R] && head<=wei)--wei;
stk[++wei] = R;
}
Ans = max(R-L,Ans);
printf("%d\n",Ans);
}