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=105000; const int N=205000; const int inf=0x7fffffff; inline int read(){ int x=0,f=1;char ch=getchar(); while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();} while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);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,1,n+1) r[i]=i-1; rep(i,1,m){ int x=read(),y=read(); r[y]=min(r[y],x-1); l[y+1]=max(l[y+1],x); } dec(i,n,1) r[i]=min(r[i+1],r[i]); rep(i,2,n+1) l[i]=max(l[i-1],l[i]); int j=1;head=0;tail=1; rep(i,1,n+1){ for(;j<=r[i]&&j<=n;j++){// 补充元素 if(f[j]==-1) 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+1?1:0); else f[i]=-1; } printf("%d\n",f[n+1]);return 0; }
完结撒花