【[HEOI2016/TJOI2016]序列】
阿新 • • 發佈:2019-01-01
ostream for tdi lowbit class std 這就是 一個 ring 分治就可以啦
壓行真漂亮
首先這肯定是一個\(dp\)了
設\(dp_i\)表示\(i\)結尾的最長不下降子序列的長度
顯然我們要找一個\(j\)來轉移
也就是\(dp_i=max(dp_j+1)\)
那麽什麽樣的\(j\)滿足條件呢
首先得是\(j<i\)
我們還註意到一個條件就是這個序列裏最多也只有一個位置會發生變化
可能是\(i\)這個位置發生變化,那麽顯然需要滿足對於任意的\(a_i\)都需要滿足大於等於\(val_j\)
於是就有\(val_j<=min_i\)
自然也有可能是前面的\(j\)發生變化,顯然就是\(max_j<=val_i\)
之後這就是一個三維偏序了,\(CDQ\)
#include<iostream> #include<cstring> #include<cstdio> #include<algorithm> #define re register #define lowbit(x) ((x)&(-x)) #define maxn 100005 #define max(a,b) ((a)>(b)?(a):(b)) #define min(a,b) ((a)<(b)?(a):(b)) inline int read() { char c=getchar();int x=0;while(c<‘0‘||c>‘9‘) c=getchar(); while(c>=‘0‘&&c<=‘9‘) x=(x<<3)+(x<<1)+c-48,c=getchar();return x; } int n,m,M; int c[maxn]; inline void add(int x,int val) {for(re int i=x;i<=M;i+=lowbit(i)) c[i]=max(c[i],val);} inline void clear(int x) {for(re int i=x;i<=M;i+=lowbit(i)) c[i]=0;} inline int ask(int x) {int now=0;for(re int i=x;i;i-=lowbit(i)) now=max(c[i],now);return now;} struct Point {int x,y,rk,ans,v;}a[maxn]; inline int cmp1(Point A,Point B) {return A.x<B.x;} inline int cmp2(Point A,Point B) {return A.v<B.v;} inline int cmp3(Point A,Point B) {return A.rk<B.rk;} void CDQ(int s,int t) { if(s==t) return; int mid=s+t>>1; CDQ(s,mid),std::sort(a+s,a+mid+1,cmp2),std::sort(a+mid+1,a+t+1,cmp1); int i=s,j=mid+1; while(i<=mid&&j<=t) if(a[i].v<=a[j].x) add(a[i].y,a[i].ans),i++; else {int now=ask(a[j].v)+1;a[j].ans=max(a[j].ans,now),j++;} while(j<=t) {int now=ask(a[j].v)+1;a[j].ans=max(a[j].ans,now),j++;} for(re int k=s;k<i;k++) clear(a[k].y); std::sort(a+mid+1,a+t+1,cmp3);CDQ(mid+1,t); } int main() { n=read(),m=read(); int A,B; for(re int i=1;i<=n;i++) a[i].x=a[i].y=read(),M=max(M,a[i].x),a[i].rk=i,a[i].ans=1,a[i].v=a[i].x; for(re int i=1;i<=m;i++) A=read(),B=read(),a[A].y=max(a[A].y,B),M=max(M,a[A].y),a[A].x=min(a[A].x,B); CDQ(1,n);int tot=0;for(re int i=1;i<=n;i++) tot=max(tot,a[i].ans);printf("%d\n",tot); return 0; }
【[HEOI2016/TJOI2016]序列】