LG3769 TATT

Posted autoint

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LG3769 TATT相关的知识,希望对你有一定的参考价值。

TATT

四维空间真是美妙。 现在有(n)个四维空间中的点,请求出一条最长的路径,满足任意一维坐标都是单调不降的。 注意路径起点是任意选择的,并且路径与输入顺序无关(路径顺序不一定要满足在输入中是升序)。

路径的长度是经过的点的数量,任意点只能经过一次。

(nleq 5 imes 10^4)

题解

https://www.luogu.com.cn/blog/hs-black/solution-p3769

这题是四维意义下的最长上升子序列, 但如果将第一维排序就变成三维问题了, kd-tree时间复杂度应该会更优

总而言之就是

[dp_i = max_{x_jle x_i,y_jle y_i,z_j le z_i} dp_j + 1 ]

从前向后扫, 找到三维都比它小的dp值最大的点, 找点可以用kd-tree来优化

可以采用以下技巧和剪枝:

  • 如果当前子树dp最大值小于等于当前已搜出的最优答案直接返回即可肯定不会更新了

  • 如果当前子树的点都在范围内, 直接拿最大值更新答案返回

  • 如果当前子树有一维的最小值超过了范围, 那么代表着这个子树中无一满足条件, 直接返回即可

  • 每次插入不用替罪羊思想重构, 可以直接提前把树建出来, 初始dp值都设为零, 加入操作相当于激活一个点, 具体就是像线段树那样从上向下搜到那个点, 返回时一路更新就行了

有了以上剪枝, 足够通过此题

CO int N=5e4+10;
array<int,4> p[N];
int q[N],ch[N][2];
array<int,3> mx[N],mn[N];

IN void push_up(int x){
	for(int i=0;i<=2;++i){
		mx[x][i]=mn[x][i]=p[x][i+1];
		if(ch[x][0]) mx[x][i]=max(mx[x][i],mx[ch[x][0]][i]),mn[x][i]=min(mn[x][i],mn[ch[x][0]][i]);
		if(ch[x][1]) mx[x][i]=max(mx[x][i],mx[ch[x][1]][i]),mn[x][i]=min(mn[x][i],mn[ch[x][1]][i]);
	}
}
int build(int l,int r,int i){
	if(l>r) return 0;
	int mid=(l+r)>>1;
	nth_element(q+l,q+mid,q+r+1,[&](int a,int b)->bool{
		return p[a][i]<p[b][i];
	});
	int x=q[mid];
	ch[x][0]=build(l,mid-1,i%3+1);
	ch[x][1]=build(mid+1,r,i%3+1);
	push_up(x);
	return x;
}

int f[N],g[N],tmp;

IN bool in(int a[],int b[]){
	for(int i=0;i<=2;++i)if(a[i]>b[i]) return 0;
	return 1;
}
void query(int x,int y){
	if(g[x]<=tmp) return;
	if(!in(mn[x].data(),p[y].data()+1)) return;
	if(in(mx[x].data(),p[y].data()+1)) {tmp=g[x]; return;}
	if(in(p[x].data()+1,p[y].data()+1)) tmp=max(tmp,f[x]);
	if(ch[x][0]) query(ch[x][0],y);
	if(ch[x][1]) query(ch[x][1],y);
}
void insert(int x,int y){
	if(x==y) {f[x]=tmp,g[x]=max(g[x],f[x]); return;}
	if(!in(p[y].data()+1,mx[x].data()) or !in(mn[x].data(),p[y].data()+1)) return;
	if(ch[x][0]) insert(ch[x][0],y),g[x]=max(g[x],g[ch[x][0]]);
	if(ch[x][1]) insert(ch[x][1],y),g[x]=max(g[x],g[ch[x][1]]);;
}

int main(){
	int n=read<int>();
	for(int i=1;i<=n;++i)
		for(int j=0;j<=3;++j) read(p[i][j]);
	sort(p+1,p+n+1,[&](CO array<int,4>&a,CO array<int,4>&b)->bool{
		for(int i=0;i<=3;++i)
			if(a[i]!=b[i]) return a[i]<b[i];
		return 0;
	});
	iota(q+1,q+n+1,1);
	int root=build(1,n,1);
	int ans=0;
	for(int i=1;i<=n;++i){
		tmp=0,query(root,i),++tmp;
		insert(root,i);
		ans=max(ans,tmp);
	}
	printf("%d
",ans);
	return 0;
}

以上是关于LG3769 TATT的主要内容,如果未能解决你的问题,请参考以下文章

P3769 [CH弱省胡策R2]TATT [KD-Tree]

题解[CH弱省胡策R2]TATT

poj 3769DNArepair

ZOJ 3769 Diablo III(分组背包)

bzoj3769

[贪心] aw3769. 移动石子(模拟)