zoukankan      html  css  js  c++  java
  • 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;
    }
    
  • 相关阅读:
    多台计算机之间数据同步——1.[转]网线制作图解教程
    离心泵的使用注意事项泄露或未排气造成扬程不够
    家庭上网用路由器和ADSL的连接
    专业FLV地址解析
    [求助]带程序访问控制的防火墙 eTrust Personal Firewall 和卡巴斯基2009引起冲突造成系统频繁死机
    DV录像带导出一定要用1394
    Cursor:url()的使用
    理解并解决JavaScript内存泄漏
    CodeIgniter的HMVC
    关于在IE下JavaScript的 Stack overflow at line 错误可能的原因
  • 原文地址:https://www.cnblogs.com/autoint/p/13168222.html
Copyright © 2011-2022 走看看