【Splay】 CF809D Hitchhiking in the Baltic States

版权声明:这是蒟蒻的BLOG,神犇转载也要吱一声哦~ https://blog.csdn.net/Dream_Lolita/article/details/89737881

【题目】
CF
有一个长度为 n n 的序列,第 i i 个数的取值范围为 [ l i , r i ] [l_i,r_i] 。求所有可能情况中,严格最长上升子序列的长度是多少。
n 3 × 1 0 5 , r i 1 0 9 n\leq 3\times 10^5,r_i\leq 10^9

【解题思路】
考虑我们平时怎么做 LIS \text{LIS} ,即设 f i f_i 表示 LIS \text{LIS} 长度为 i i 时,结尾最小值。

现在考虑插入一个数 [ l , r ] [l,r] 可以更新的值,那么我们找到小于 l l 的第一个位置 x x 和小于 r r 的第一个位置 y y ,则 f x + 1 f_{x+1} 可以更新为 L L i [ x + 2 , y ] i\in [x+2,y] 可以更新为 f i = f i 1 + 1 f_i=f_{i-1}+1 ,即将数组右移再区间 + 1 +1 。那么我们需要支持删除 y + 1 y+1 ,插入 f x + 1 = L f_{x+1}=L

splay \text{splay} 维护,最后有用节点个数就是答案了。复杂度 O ( n log n ) O(n\log n)

【参考代码】

在#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;
}

猜你喜欢

转载自blog.csdn.net/Dream_Lolita/article/details/89737881