zoukankan      html  css  js  c++  java
  • [正睿集训2021] LIS

    一、题目

    点此看题

    二、解法

    (dp[i]) 为到 (i) 的最大长度,那么当 (a_j imes x_i+b_jgeq y_i) 可以转移:

    [dp[i]=dp[j]+1 ]

    这个题没有掩饰啊,直接就把一次函数甩给你了,摆明了就是要让你用李超树。具体来说转移 (i) 的时候有 ([1,i)) 这些线段,(x_ileq300000) 说明它可以作为李超树的下标。

    但是李超树不是只能解决一次函数的最值吗?怎么又和不等式扯上关系的?我们可以二分答案 (x) ,那么对于 (dp) 值在 ([x,n]) 的线段都是可以用的,我们求出他在 (x_i) 的最值是否大于 (y) 即可。

    但是要保留 ([x,n]) 的线段并不是很容易,我们可以使用树套树来解决这个问题,也就是外层线段树,内层李超树,李超树要动态开点,那么我们在线段树上二分就行了,由于李超树是全局线段所以复杂度是一个 (log)

    那么时间复杂度 (O(nlog^2 n)),空间复杂度 (O(nlog n)) ,看起来很好写是吧。

    但是我的答案输出成了 (dp[n]) ,实际上应该是 (max_{i=1}^n dp[i]),老子调了好久,( t cnm)( t sb) 题。

    #include <cstdio>
    #include <iostream>
    using namespace std;
    const int M = 150005;
    const int N = 50*M;
    const int up = 300000;
    const int inf = 0x3f3f3f3f;
    #define int long long
    int read()
    {
    	int x=0,f=1;char c;
    	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
    	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
    	return x*f;
    }
    int T,n,cnt,ans,a[M],b[M],x[M],y[M],dp[M],rt[4*M],ls[N],rs[N];
    struct node
    {
    	int k,b;
    	node(int K=0,int B=-inf) : k(K) , b(B) {}
    	void clear() {k=0;b=-inf;}
    	int ask(int x)
    	{
    		return x*k+b;
    	}
    }tr[N];
    void upd(int &i,int l,int r,node x)
    {
    	if(!i)
    	{
    		i=++cnt;
    		ls[i]=rs[i]=0;tr[i].clear(); 
    	} 
    	int mid=(l+r)>>1;
    	if(x.ask(mid)>tr[i].ask(mid))
    	{
    		if(x.ask(l)<tr[i].ask(l)) upd(ls[i],l,mid,tr[i]);
    		if(x.ask(r)<tr[i].ask(r)) upd(rs[i],mid+1,r,tr[i]);
    		tr[i]=x;
    	}
    	if(x.ask(mid)<tr[i].ask(mid))
    	{
    		if(x.ask(l)>tr[i].ask(l)) upd(ls[i],l,mid,x);
    		if(x.ask(r)>tr[i].ask(r)) upd(rs[i],mid+1,r,x);
    	}
    }
    int ask(int i,int l,int r,int x)
    {
    	if(!i) return -inf;
    	int mid=(l+r)>>1,res=tr[i].ask(x);
    	if(l==r) return res;
    	if(mid>=x) return max(ask(ls[i],l,mid,x),res);
    	return max(ask(rs[i],mid+1,r,x),res);
    }
    void ins(int i,int l,int r,int id,node x)
    {
    	upd(rt[i],0,up,x);
    	if(l==r) return ;
    	int mid=(l+r)>>1;
    	if(mid>=id) ins(i<<1,l,mid,id,x);
    	else ins(i<<1|1,mid+1,r,id,x);
    }
    int solve(int i,int l,int r,int x,int y) 
    {
    	if(ask(rt[i],0,up,x)<y)
    		return 0;
    	if(l==r) return l;
    	int mid=(l+r)>>1;
    	if(ask(rt[i<<1|1],0,up,x)>=y)
    		return solve(i<<1|1,mid+1,r,x,y);
    	if(ask(rt[i<<1],0,up,x)>=y) 
    		return solve(i<<1,l,mid,x,y);
    }
    signed main()
    {
    	T=read();
    	while(T--)
    	{
    		n=read();cnt=ans=0;//nmsl
    		for(int i=1;i<=4*n;i++) rt[i]=0;
    		for(int i=1;i<=n;i++)
    		{
    			a[i]=read();b[i]=read();
    			x[i]=read();y[i]=read();
    		}
    		for(int i=1;i<=n;i++)
    		{
    			dp[i]=solve(1,1,n,x[i],y[i])+1;
    			ins(1,1,n,dp[i],node(a[i],b[i]));
    		}
    		for(int i=1;i<=n;i++)
    			ans=max(ans,dp[i]);
    		printf("%lld
    ",ans);
    	}
    }
    
  • 相关阅读:
    点云平台之图像算法篇
    点云平台之CloudCompare开发
    点云平台之创建工程文件
    pcl介绍
    原型讲解二:原型是干什么用的
    原型讲解一
    博主平时主要发布什么?
    蒙特利尔大学工学院流程
    ubuntu 开热点
    argos3-simulator
  • 原文地址:https://www.cnblogs.com/C202044zxy/p/14223983.html
Copyright © 2011-2022 走看看