TJOI2013 最长上升子序列

维护动态序列 支持插入和查询区间最大值

平衡树上要维护两个权值:
一个是这个点所代表的dp值
一个是val值 代表dp最大值 两个不能重叠 否则在分裂的时候会出错

#include <iostream>
#include <cstdio>
#include <cstring>
#include <ctime>
#include <cstdlib>
using namespace std;
const int N=2e5+10;
int read()
{
    int x=0,f=0,c=getchar();
    while(c<'0'||c>'9'){if(c=='-')f=1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    return f?-x:x; 
}

int sz[N],lch[N],rch[N],rnd[N],dp[N],val[N],pos[N];
int root,rx,ry,rz,cnt;
int n,m;
//注意这题有个特殊的条件: 加入的数一直是递增的
//所以当前序列中已经有的值一定比较小

void upd(int x)
{ 
	sz[x]=sz[lch[x]]+sz[rch[x]]+1;
	val[x]=max( max(val[lch[x]],val[rch[x]]), dp[ pos[x]] );
}

void split(int now,int k,int &x,int &y)
{
	if(!now){ x=y=0; return;}
	if(k>=sz[lch[now]]+1){ x=now; split(rch[now],k-sz[lch[now]]-1,rch[x],y);}
	else { y=now; split(lch[now],k,x,lch[y]);}
	upd(now);
}

int merge(int x,int y)
{
	if(!x||!y) { return x+y;}
	if(rnd[x]<rnd[y]){ rch[x]=merge(rch[x],y); upd(x); return x;}
	else { lch[y]=merge(x,lch[y]); upd(y); return y;}
}

int _new(int x,int i){ rnd[++cnt]=rand(); sz[cnt]=1; dp[i]=x;val[cnt]=x; pos[cnt]=i;return cnt;}

int main()
{
	srand(1);
	n=read();
	for(int i=1;i<=n;i++)
	{
		int p=read()+1;
		split(root,p-1,rx,ry);
		root=merge( merge(rx,_new( val[rx]+1,i ) ) ,ry) ;
		printf("%d\n",val[root]);
	}
	return 0;
}
posted @   __iostream  阅读(27)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示