三维偏序-二维LIS
Another Longest Increasing Subsequence Problem
有两种思路。
思路一:
考虑到如果只有一维,那么可以用f[s]表示长度为s时,最后一个数是多少,把这个想法拓展到二维,即f[s]表示长度为s时,最后一个点的集合,也就是说有多个点,但是这多个点是有顺序,x递增,y递减,并且每次加点进来的时候,随时保持这个顺序。
关于怎么处理点的集合,可以用平衡树来实现,这里用map来代替,而且map自带二分查找的功能。
算法实现:采用二分答案的方法,初始区间是(0,ans)这是刚好合适的情况,每次二分的时候,要验证两个值mid和mid+1,如果只验证mid,成立的时候跳向(mid+1,r),但是这个区间上可能找不到答案,这和二分查找不一样,这是找最优解,而不是验证存不存在,所以至少要保证mid+1成立才能考查右区间。
最后更新的时候,记住保持x递增,y递减的顺序就可以了,情况比较多,很繁琐,我在这里错了很久,注意边界处的细节怎么处理,详细的看代码。
代码如下:
#include<bits/stdc++.h>
#define rep(i,n) for(i=1;i<=n;i++)
#define F first
#define S second
using namespace std;
const int maxn=100100;
map<int,int>f[maxn];
int n;
int find(int x,int y,int l,int r)
{
if(l==r)return l;
int mid=(l+r)>>1;
map<int,int>::iterator it1,it2;
it1=f[mid].lower_bound(x);
it2=f[mid+1].lower_bound(x);
if(it1==f[mid].begin() || it2==f[mid+1].begin())return find(x,y,l,mid);
--it1,--it2;
if(it1->S>=y || it2->S>=y)return find(x,y,l,mid);
return find(x,y,mid+1,r);
}
void update(int x,int y,int p)
{
map<int,int>::iterator it1=f[p].lower_bound(x),it2=it1;
if(it1!=f[p].end() && it1->F == x && it1->S<=y)return ;
if(it1!=f[p].begin() && (--it1)->S<=y)return ;
while(it2!=f[p].end() && it2->S>=y)f[p].erase(it2++);
f[p][x]=y;
}
int main()
{
int i,ans=0;
scanf("%d",&n);
f[0][-2000000000]=-2000000000;
rep(i,n)
{
int x,y;
scanf("%d%d",&x,&y);
int pos=find(x,y,0,ans);
ans=max(ans,++pos);
update(x,y,pos);
}
printf("%d",ans);
}
方法二:CDQ分治。
采用分治的思想,先处理左区间,再用左区间更新一次右区间,再处理右区间,这样就保证每次处理的时候都是用前面的更新过的。
一共有三维的坐标x:点的下标,y:点的横坐标,z:点的纵坐标。分治的时候,因为是用左区间来更新右区间,所以x保证是升序的,可以左右区间分别将y排序,每次更新右区间的时候,都依次遍历看哪些左区间的点可以加进去,可以用数据结构进行转移(线段树,树状数组都可以,只是线段树在本题中会超时),将离散化后的z坐标作为下标,f[x]作为值对数组数组(或线段树)进行更新,查询符合条件的f 最大值。每次转移完成后,要把线段树或树状数组清空,不要用memset,更新了哪些就清空哪些。最后还要将区间上的点按x的顺序重新排好序,保证接下来处理的时候x是升序的。
注意:sort(a+st,a+ed,cmp)实际上是对(a[st],a[ed-1])之间的元素进行排序!
代码如下(线段树):
#include<bits/stdc++.h>
#define rep(i,n) for(i=1;i<=n;i++)
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
using namespace std;
const int maxn=100100;
int tree[maxn*4],f[maxn],a[maxn];
struct zz{int x,y,z;}poi[maxn];
int n;
bool cmpy(const zz& i,const zz&j)
{
return i.y<j.y;
}
bool cmpx(const zz&i,const zz&j)
{
return i.x<j.x;
}
int find(int v,int l,int r)
{
int mid=(l+r)>>1;
if(l==r)return l;
if(v<=a[mid])return find(v,l,mid);
return find(v,mid+1,r);
}
void update(int p,int add,int l,int r,int rt)
{
if(l==r)
{
tree[rt]=(add==0?add:max(tree[rt],add));
return ;
}
int mid=(l+r)>>1;
if(p<=mid)update(p,add,lson);
else update(p,add,rson);
tree[rt]=max(tree[rt<<1],tree[rt<<1|1]);
}
int query(int L,int R,int l,int r,int rt)
{
if(L>R)return 0;
if(l>=L && r<=R)return tree[rt];
int mid=(l+r)>>1;
if(mid>=R)return query(L,R,lson);
if(mid<L)return query(L,R,rson);
return max(query(L,R,lson),query(L,R,rson));
}
void work(int l,int r)
{
int mid=(l+r)>>1;
sort(poi+l,poi+mid+1,cmpy);
sort(poi+mid+1,poi+r+1,cmpy);
for(int i=l,j=mid+1;j<=r;j++)
{
while(poi[i].y<poi[j].y && i<=mid)
{
update(poi[i].z,f[poi[i].x],1,n,1);
i++;
}
f[poi[j].x]=max(f[poi[j].x],query(1,poi[j].z-1,1,n,1)+1);
}
for(int i=l;i<=mid;i++)update(poi[i].z,0,1,n,1);
sort(poi+mid+1,poi+r+1,cmpx);
}
void CDQ(int l,int r)
{
int mid=(l+r)>>1;
if(l==r)return;
CDQ(l,mid);
work(l,r);
CDQ(mid+1,r);
}
int main()
{
// freopen("D.in","r",stdin);
// freopen("D.out","w",stdout);
// ios::sync_with_stdio(false);
//cin>>n;
scanf("%d",&n);
int i;
rep(i,n)
{
// cin>>poi[i].y>>poi[i].z;
scanf("%d%d",&poi[i].y,&poi[i].z);
a[i]=poi[i].z;
poi[i].x=i;
f[i]=1;
}
sort(a+1,a+n+1);
rep(i,n)poi[i].z=find(poi[i].z,1,n);
//rep(i,n)cout<<poi[i].z<<endl;
CDQ(1,n);
int ans=0;
rep(i,n) ans=max(ans,f[i]);
// rep(i,n)cout<<f[i]<<endl;
//ios::sync_with_stdio(true);
// cout<<ans<<endl;
printf("%d",ans);
return 0;
}
三维偏序-二维LIS的更多相关文章
- HDU 1160 FatMouse's Speed(要记录路径的二维LIS)
FatMouse's Speed Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) ...
- BZOJ2244: [SDOI2011]拦截导弹(CDQ分治,二维LIS,计数)
Description 某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统.但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度.并且能够拦截任意速度的导弹,但是以后每一发炮弹都不能高 ...
- 二维LIS(CDQ分治)
题目描述 给定一个长度为N的序列S,S的每个元素pi是一个二元组(xi,yi),定义pi<pj当且仅当xi<xj并且yi<yj,求S的最长上升子序列长度 输入格式 第一行一个N,表示 ...
- 三维码 & 二维码 & 一维码
三维码 & 二维码 & 一维码 3D, 2D, 1D 防伪国家标准 -<结构三维码防伪技术条件> http://www.xinhuanet.com/tech/2019-12 ...
- HDU 1025 Constructing Roads In JGShining's Kingdom(二维LIS)
Constructing Roads In JGShining's Kingdom Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65 ...
- ACdream 1216——Beautiful People——————【二维LIS,nlogn处理】
Beautiful People Special Judge Time Limit: 2000/1000MS (Java/Others) Memory Limit: 128000/64000KB (J ...
- 【opencv】projectPoints 三维点到二维点 重投影误差计算
今天计算rt计算误差——重投影误差 用solvepnp或sovlepnpRansac,输入3d点.2d点.相机内参.相机畸变,输出r.t之后 用projectPoints,输入3d点.相机内参.相机畸 ...
- TanksWar(坦克大战三维、二维版以及90版)
本文已迁移至:https://coco56.blog.csdn.net/article/details/103198945
- SGU 521 North-East ( 二维LIS 线段树优化 )
521. "North-East" Time limit per test: 0.5 second(s)Memory limit: 262144 kilobytes input: ...
随机推荐
- hdu 1215 七夕节
Problem Description 七夕节那天,月老来到数字王国,他在城门上贴了一张告示,并且和数字王国的人们说:"你们想知道你们的另一半是谁吗?那就按照告示上的方法去找吧!" ...
- 【原创】C++中对象的序列化
1.对象序列化 对象的序列化是指将对象的状态信息转换为可以存储或者传输的形式的过程.对象的反序列化是与序列化相反的过程. 在序列化期间,对象将其当前的状态写入到临时或者永久性的存储区,可以通过从存储区 ...
- POJ 3352 无向图边双连通分量,缩点,无重边
为什么写这道题还是因为昨天多校的第二题,是道图论,HDU 4612. 当时拿到题目的时候就知道是道模版题,但是苦于图论太弱.模版都太水,居然找不到. 虽然比赛的时候最后水过了,但是那个模版看的还是一知 ...
- 火狐下<a>标签里嵌套的<select>不能选的bug
今天遇到了这个问题,网上一找就找到原因了:在狐火下<a>标签里嵌套的<select>不能选 可是我查找这个问题过程中依然饶了一些时间,原因是在<a>标签没有写hre ...
- IE CSS Bug 系列
1.[IE CSS Bug系列]IE6&IE7图片链接无效 <!doctype html> <html> <head> <meta charset=& ...
- python爬虫下载youtube单个视频
__author__ = 'Sentinel'import requestsimport reimport jsonimport sysimport shutilimport urlparse &qu ...
- python学习第一天 -安装配置及其输入输出
Python, 是一种面向对象.解释型计算机程序设计语言. python适合领域: 1.Web网络和各种网络服务 2.系统工具和脚本 3.作为“胶水”语言把其他语言开发的模块包装起来方便使用 pyth ...
- js与webview 常用交互代码
常用js交互 css常用参数::: 是否允许用户选择元素的内容,选择值包括: auto:用户可以选择元素内的内容 none:用户不能选择任何内容 text:用户只能选择元素内的 ...
- windows完全支持C++11的轻量级编译器(官网MinGW和非官方的MinGW-builds)
作者:网事如风链接:https://www.zhihu.com/question/22923569/answer/23172337来源:知乎著作权归作者所有,转载请联系作者获得授权. 完全支持C++1 ...
- highchart 实现mrtg
最近需要对流量图进行重构, <%@ page language="java" contentType="text/html; charset=UTF-8" ...