首先LIS有个$O(n^2)$的DP方法
$f(i,j)$表示前i个数,最后一个数<=j的LIS
如果$a_i!=0$则有
如果$a_i=0$则有
注意因为$f(i-1,j)leq f(i-1,j-1)+1$,所以上面第二个转移是成立的。
用treap维护这个有两种写法。
①支持区间max=,区间+1。
②只要是只要求单点查询或者最后输出答案的区间操作都是可以用差分的。
这题显然两个条件都满足233
每次对一个区间+1的时候,实际上就是区间后移一位,直接插入一个点即可,然后l所在位置+1,(r+1)所在位置-1,但是这题我们维护的是前缀max,所以每个点的信息其实是前面任意一个地方的差分值里最大的,所以我们不能-1,而是如果区间右端点右边还有+1的话,就删掉最近的一个。
$a_i=0$时,区间为$[l,r]$,$a_i!=0$,区间看成是$a_i$这个点。
好像写丑了跑得很慢

#include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #define lt tree[x].ls #define rt tree[x].rs using namespace std; const int maxn=500010; struct poi{int ls, rs, sum, rnd, size, w;}tree[maxn]; int n, l, r, tott, root, tmp, mx, now, cnt; int a[maxn]; inline void read(int &k) { int f=1; k=0; char c=getchar(); while(c<'0' || c>'9') c=='-' && (f=-1), c=getchar(); while(c<='9' && c>='0') k=k*10+c-'0', c=getchar(); k*=f; } inline void build(int &x, int delta) { tree[x=++tott].w=tree[x].sum=delta; tree[x].rnd=rand()<<15|rand(); tree[x].size=1; } inline void up(int x) { tree[x].size=tree[lt].size+tree[rt].size+1; tree[x].sum=tree[lt].sum+tree[rt].sum+tree[x].w; } void split(int x, int &l, int &r, int k) { if(!k) l=0, r=x; else if(tree[x].size==k) l=x, r=0; else if(tree[lt].size>=k) r=x, split(lt, l, lt, k), up(x); else l=x, split(rt, rt, r, k-tree[lt].size-1), up(x); } void merge(int &x, int l, int r) { if(!l || !r) x=l+r; else if(tree[l].rnd>tree[r].rnd) x=l, merge(rt, rt, r), up(x); else x=r, merge(lt, l, lt), up(x); } void find(int x) { if(tree[lt].sum) return find(lt); now+=tree[lt].size+1; if(tree[x].w) return; if(tree[rt].sum) return find(rt); } void del(int &root, int rk) { int x, y, z; split(root, x, y, rk); split(x, z, x, rk-1); merge(root, z, y); } inline void solve(int l, int r) { int x, y, z; build(tmp, 1); split(root, x, y, l-1); merge(x, x, tmp); merge(root, x, y); split(root, x, y, r); if(tree[y].sum) {now=0; find(y); del(y, now);} merge(root, x, y); split(root, x, y, mx); merge(root, x, y); } int main() { read(n); read(l); read(r); tree[0].rnd=(1ll<<31)-1; mx=r; for(int i=1;i<=n;i++) read(a[i]), mx=max(mx, a[i]); for(int i=1;i<=mx;i++) build(tmp, 0), merge(root, root, tmp); for(int i=1;i<=n;i++) if(a[i]) solve(a[i], a[i]); else solve(l, r); int x, y; split(root, x, y, mx); printf("%d ", tree[x].sum); }