luogu 3084 单调队列+dp

时间:2023-03-08 23:58:26
luogu 3084 单调队列+dp

注意处理出两个数组:

r[i] 能覆盖i点的区间的左端点最小值(覆盖左侧最远处)

l[i] i不能覆盖的区间的左端点左端点最大值

在该区间内寻找用来更新f[i] 答案的 j

即 l[i]<= j <= r[i]

转移方程: f[i] = max (f[j] )+1;

利用单调队列维护滑动窗口

但是由于不定长,与一般的单调队列稍有区别,利用指针 j 将区间内的元素补充进队列中

#include<bits/stdc++.h>
#define rep(i,x,y) for(register int i=x;i<=y;i++)
#define dec(i,x,y) for(register int i=x;i>=y;i--)
using namespace std; const int M=;
const int N=;
const int inf=0x7fffffff; inline int read(){
int x=,f=;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-;ch=getchar();}
while(isdigit(ch)){x=(x<<)+(x<<)+(ch^);ch=getchar();}
return x*f;}
int n,m,a[M],b[M],l[N],r[N],q[N],f[N],head,tail; int main(){
n=read(),m=read();
rep(i,,n+) r[i]=i-;
rep(i,,m){
int x=read(),y=read();
r[y]=min(r[y],x-);
l[y+]=max(l[y+],x);
}
dec(i,n,) r[i]=min(r[i+],r[i]);
rep(i,,n+) l[i]=max(l[i-],l[i]); int j=;head=;tail=;
rep(i,,n+){
for(;j<=r[i]&&j<=n;j++){// 补充元素
if(f[j]==-) continue;
while(head<=tail&&f[q[tail]]<f[j]) tail--;
q[++tail]=j;
}
while(head<=tail&&q[head]<l[i]) head++; if(head<=tail) f[i]=f[q[head]]+(i!=n+?:);
else f[i]=-;
}
printf("%d\n",f[n+]);return ;
}

完结撒花