CF809D
好神奇的数据结构呀...
首先我们考虑:暴力怎么做?
设状态$dp[j]$表示长度为$j$的序列最后一个数最小是几,如果$j$位置的限制区间为$[l,r]$,那么显然有转移:
$dp[j]=l(dp[j-1]<l)$
$dp[j]=dp[j-1]+1(l\leq dp[j-1]\leq r-1)$
$dp[j]=dp[j] (dp[j-1] \geq r)$
正确性显然
考虑优化:我们考虑上面三个操作的实质:
第一个转移方向:在$l$的前驱后面插入$l$
第二个转移方向:把区间$[l,r-1]$整体加一,之后右移一格(相当于向后转移了一个位置)
第三个转移方向:删去$r$的后继
那么用平衡树直接实现上面三个操作即可,考虑到每次都有插入操作,因此事实上第二个操作不需要真正右移,只需加一即可
强烈建议fhq_treap实现
代码:
#include <cstdio> #include <cmath> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> #include <queue> #include <stack> #include <ctime> #define ls tree[rt].lson #define rs tree[rt].rson using namespace std; struct FHQ_TREAP { int lson,rson; int siz; int val,rank; int lazy; }tree[300005]; int tot=0; int rot,re,n; void pushup(int rt) { tree[rt].siz=tree[ls].siz+tree[rs].siz+1; } void pushdown(int rt) { if(!rt)return; if(ls)tree[ls].lazy+=tree[rt].lazy,tree[ls].val+=tree[rt].lazy; if(rs)tree[rs].val+=tree[rt].lazy,tree[rs].lazy+=tree[rt].lazy; tree[rt].lazy=0; } int new_node(int v) { int ret=++tot; tree[ret].siz=1,tree[ret].val=v,tree[ret].rank=rand(); return ret; } int merge(int x,int y) { if((!x)||(!y))return x|y; if(tree[x].lazy)pushdown(x); if(tree[y].lazy)pushdown(y); if(tree[x].rank<tree[y].rank) { tree[x].rson=merge(tree[x].rson,y); pushup(x); return x; }else { tree[y].lson=merge(x,tree[y].lson); pushup(y); return y; } } void split(int rt,int k,int &x,int &y) { if(!rt){x=y=0;return;} if(tree[rt].lazy)pushdown(rt); if(tree[rt].val<=k)x=rt,split(rs,k,rs,y); else y=rt,split(ls,k,x,ls); pushup(rt); } void ins(int v) { int x,y; split(rot,v,x,y); rot=merge(merge(x,new_node(v)),y); } void del(int v) { int x,y,z,w; split(rot,v,x,y); split(x,v-1,z,w); w=merge(tree[w].lson,tree[w].rson); rot=merge(merge(z,w),y); } void update(int rt,int l,int r) { int x,y,z,w; split(rot,l-1,x,y); split(y,r,z,w); if(z)tree[z].lazy++,tree[z].val++; rot=merge(x,merge(z,w)); } void get_pro(int rt,int v) { if(!rt)return; if(v<=tree[rt].val)get_pro(ls,v); else re=tree[rt].val,get_pro(rs,v); } int get_minn(int rt) { if(!ls)return tree[rt].val; else return get_minn(ls); } int get_sub(int v) { int x,y; split(rot,v,x,y); int ret=get_minn(y); rot=merge(x,y); return ret; } inline int read() { int f=1,x=0;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } void solve() { srand(time(NULL)); n=read(); for(int i=1;i<=n;i++) { int l=read(),r=read(); if(i==1){ins(l);continue;} re=get_sub(r-1); update(rot,l,r-1); if(re)del(re); ins(l); } if(!rot)printf("0\n"); else printf("%d\n",tree[rot].siz); } int main() { solve(); return 0; }