bzoj 3126 单调队列优化dp
能转移的最左是其左边完整区间的最右左端点,最右是能覆盖它的最左左端点-1
#pragma GCC optimize ("O3") #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<cmath> #define N 200005 using namespace std; int l[N],r[N],n,m,f[N],q[N]; int read(){ int a=0;char ch=getchar(); while(ch<'0'||ch>'9')ch=getchar(); while(ch>='0'&&ch<='9'){a=a*10+(ch^48);ch=getchar();} return a; } int main(){ n=read(); m=read(); for(register int i=1;i<=n+1;++i)r[i]=i-1; for(register int i=1,x,y;i<=m;++i){ x=read(); y=read(); r[y]=min(r[y],x-1); l[y+1]=max(l[y+1],x); } for(register int i=2;i<=n+1;++i) l[i]=max(l[i],l[i-1]); for(register int i=n;i>=1;--i) r[i]=min(r[i],r[i+1]); /*for(int i=1;i<=n;i++) printf("%d %d %d\n",i,l[i],r[i]);*/ for(register int i=1,j=1,head=1,tail=1;i<=n+1;++i){ while(j<=r[i]&&j<=n){ if(f[j]==-1){j++;continue;} while(head<=tail&&f[j]>f[q[tail]])--tail; q[++tail]=j++; } while(head<=tail&&q[head]<l[i])++head; if(head<=tail)f[i]=f[q[head]]+1; else f[i]=-1; //printf("%d %d\n",i,f[i]); } if(f[n+1]==-1)printf("%d\n",f[n+1]); else printf("%d\n",f[n+1]-1); return 0; }
人生如梦亦如幻 朝如晨露暮如霞。