【题目】
CF
有一个长度为
n
n
n的序列,第
i
i
i个数的取值范围为
[
l
i
,
r
i
]
[l_i,r_i]
[li,ri]。求所有可能情况中,严格最长上升子序列的长度是多少。
n
≤
3
×
1
0
5
,
r
i
≤
1
0
9
n\leq 3\times 10^5,r_i\leq 10^9
n≤3×105,ri≤109
【解题思路】
考虑我们平时怎么做
LIS
\text{LIS}
LIS,即设
f
i
f_i
fi表示
LIS
\text{LIS}
LIS长度为
i
i
i时,结尾最小值。
现在考虑插入一个数 [ l , r ] [l,r] [l,r]可以更新的值,那么我们找到小于 l l l的第一个位置 x x x和小于 r r r的第一个位置 y y y,则 f x + 1 f_{x+1} fx+1可以更新为 L L L, i ∈ [ x + 2 , y ] i\in [x+2,y] i∈[x+2,y]可以更新为 f i = f i − 1 + 1 f_i=f_{i-1}+1 fi=fi−1+1,即将数组右移再区间 + 1 +1 +1。那么我们需要支持删除 y + 1 y+1 y+1,插入 f x + 1 = L f_{x+1}=L fx+1=L。
用 splay \text{splay} splay维护,最后有用节点个数就是答案了。复杂度 O ( n log n ) O(n\log n) O(nlogn)
【参考代码】
在#include<bits/stdc++.h>
using namespace std;
const int N=3e5+10,inf=0x3f3f3f3f;
int read()
{
int ret=0;char c=getchar();
while(!isdigit(c)) c=getchar();
while(isdigit(c)) ret=ret*10+(c^48),c=getchar();
return ret;
}
struct Splay
{
#define ls ch[x][0]
#define rs ch[x][1]
int rt,sz,rb;
int rub[N],fa[N],tag[N],val[N],ch[N][2];
void pushdown(int x)
{
if(!tag[x]) return;
val[ls]+=tag[x];val[rs]+=tag[x];tag[ls]+=tag[x];tag[rs]+=tag[x];tag[x]=0;
}
int get(int x){return ch[fa[x]][1]==x;}
void rotate(int x)
{
int y=fa[x],z=fa[y],k=get(x);
pushdown(y);pushdown(x);
if(z) ch[z][get(y)]=x;
fa[y]=x;fa[x]=z;fa[ch[x][!k]]=y;
ch[y][k]=ch[x][!k];ch[x][!k]=y;
}
void splay(int x,int goal)
{
while(fa[x]!=goal)
{
int y=fa[x];
if(fa[y]!=goal) rotate(get(y)==get(x)?y:x);
rotate(x);
}
if(!goal) rt=x;
}
void emp(int x){val[x]=fa[x]=tag[x]=ls=rs=0;}
int newnode(int v)
{
int x=0;
if(rb) x=rub[rb--]; else x=++sz;
emp(x);val[x]=v;
return x;
}
void build()
{
newnode(inf);newnode(-inf);fa[2]=1;ch[1][0]=2;rt=1;
}
void insert(int &x,int v,int f)
{
if(!x){x=newnode(v);fa[x]=f;splay(x,0);return;}
pushdown(x);
insert(ch[x][v>val[x]],v,x);
}
void erase(int x)
{
splay(x,0);
int l=ls,r=rs;
while(ch[l][1]) l=ch[l][1];
while(ch[r][0]) r=ch[r][0];
splay(l,0);splay(r,l);
ch[r][0]=0;emp(x);rub[++rb]=x;
}
int findl(int v)
{
int x=rt,res=0;
while(x)
{
pushdown(x);
if(val[x]<v) res=x,x=rs; else x=ls;
}
return res;
}
int findsuc(int x)
{
splay(x,0);x=rs;
while(ls) x=ls;
return x;
}
void solve(int l,int r)
{
int x=findl(l),y=findl(r),p=findsuc(y);
//printf("%d %d %d\n",x,y,p);
if(x^y) splay(x,0),splay(p,x),tag[ch[p][0]]++,val[ch[p][0]]++;
if(p^1) erase(p);
insert(rt,l,0);
}
void dfs(int x)
{
if(!x) return;
dfs(ls);
printf("%d %d %d %d\n",x,ls,rs,val[x]);
dfs(rs);
}
void debug()
{
puts("debug=============");
dfs(rt);
puts("endbug============");
}
#undef ls
#undef rs
}T;
int main()
{
#ifdef Durant_Lee
freopen("CF809D.in","r",stdin);
freopen("CF809D.out","w",stdout);
#endif
int Q=read();T.build();
for(int i=1,l,r;i<=Q;++i) l=read(),r=read(),T.solve(l,r);
printf("%d\n",T.sz-2-T.rb);
return 0;
}