【坐标变换】【二维偏序】【线段树】Gym - 100820G - Racing Gems
题意:第一象限有n个点,你从x正半轴任选一个位置出发,vy恒定,vx可以任意变化,不过只能在-vy/r到vy/r之间变化,问你最多能经过多少个点。
暴力dp是n^2,不可取。
注意到,一个点,所能到达它的点,是它后面一个张角内的所有点。这个张角很容易算出。
于是可以将这些点全部映射到一个新的坐标系内,使得这个坐标系内每个点左下方的点都是能到达它的点。(没必要真的算出那些真的变换后的坐标,可以以到那个虚拟张角的两条边的距离作为坐标,这样虽然扭曲了一点,但不影响答案。)
于是转化成了二维偏序问题,可以用一维排序+一维线段树维护左下方的最大值来解决。
注意是实数点,离散化的时候要处理好误差。
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
const double eps=0.0000001;
struct Point{
double x,y;
Point(const double &x,const double &y){
this->x=x;
this->y=y;
}
Point(){}
void read(){
scanf("%lf%lf",&x,&y);
}
double length(){
return sqrt(x*x+y*y);
}
}a[100005];
typedef Point Vector;
Vector operator - (const Point &a,const Point &b){
return Vector(a.x-b.x,a.y-b.y);
}
double Cross(const Vector &a,const Vector &b){
return a.x*b.y-a.y*b.x;
}
double DisToLine(Point P,Point A,Point B)
{
Vector v1=B-A,v2=P-A;
return fabs(Cross(v1,v2))/v1.length();
}
int n,r,w,h;
pair<double,int> b[100005];
struct data{
double v;
int p;
data(const double &v,const int &p){
this->v=v;
this->p=p;
}
data(){}
}t[100005];
bool cmp(const data &a,const data &b){
return a.v<b.v;
}
bool cm2(const pair<double,int> &a,const pair<double,int> &b){
return a.second<b.second;
}
int ans;
int maxv[100005<<2];
void update(int p,int v,int rt,int l,int r){
if(l==r){
maxv[rt]=v;
return;
}
int m=(l+r>>1);
if(p<=m){
update(p,v,rt<<1,l,m);
}
else{
update(p,v,rt<<1|1,m+1,r);
}
maxv[rt]=max(maxv[rt<<1],maxv[rt<<1|1]);
}
int query(int ql,int qr,int rt,int l,int r){
if(ql<=l && r<=qr){
return maxv[rt];
}
int m=(l+r>>1),res=0;
if(ql<=m){
res=max(res,query(ql,qr,rt<<1,l,m));
}
if(m<qr){
res=max(res,query(ql,qr,rt<<1|1,m+1,r));
}
return res;
}
int main(){
//freopen("g.in","r",stdin);
scanf("%d%d%d%d",&n,&r,&w,&h);
Point p=Point((double)w*0.5,-(double)w*(double)r*0.5);
Point q=Point((double)w,0.0);
Point yd=Point(0.0,0.0);
for(int i=1;i<=n;++i){
a[i].read();
double d1=DisToLine(a[i],p,q);
double d2=DisToLine(a[i],p,yd);
a[i]=Point(d1,d2);
b[i].first=d1;
t[i].v=d2;
t[i].p=i;
}
sort(t+1,t+n+1,cmp);
int zy=0;
b[t[1].p].second=++zy;
for(int i=2;i<=n;++i){
if(fabs(t[i].v-t[i-1].v)>eps){
++zy;
}
b[t[i].p].second=zy;
}
int sta;
sort(b+1,b+n+1);
for(int i=1;i<=n;++i){
if(i==1 || fabs(b[i].first-b[i-1].first)>eps){
sta=i;
}
if(i==n || fabs(b[i].first-b[i+1].first)>eps){
sort(b+sta,b+i+1,cm2);
for(int j=sta;j<=i;++j){
int x=query(1,b[j].second,1,1,zy);
ans=max(ans,x+1);
update(b[j].second,x+1,1,1,zy);
}
}
}
printf("%d\n",ans);
return 0;
}
【坐标变换】【二维偏序】【线段树】Gym - 100820G - Racing Gems的更多相关文章
- 二维$MLE$线段树
关于二维线段树,ta死了 先来看看两种二维线段树的打法 1.四叉树 然而ta死了,ta是$\Theta (n)$的,加上线段树的常数,$T$飞稳 2.线段树套线段树 我尽量画出来... 图中每个方块是 ...
- SGU 521 North-East ( 二维LIS 线段树优化 )
521. "North-East" Time limit per test: 0.5 second(s)Memory limit: 262144 kilobytes input: ...
- [luogu4479][BJWC2018]第k大斜率【二维偏序+二分+离散化+树状数组】
传送门 https://www.luogu.org/problemnew/show/P4479 题目描述 在平面直角坐标系上,有 n 个不同的点.任意两个不同的点确定了一条直线.请求出所有斜率存在的直 ...
- 二维偏序+树状数组【P3431】[POI2005]AUT-The Bus
Description Byte City 的街道形成了一个标准的棋盘网络 – 他们要么是北南走向要么就是西东走向. 北南走向的路口从 1 到 n编号, 西东走向的路从1 到 m编号. 每个路口用两个 ...
- 【二维偏序】【树状数组】【权值分块】【分块】poj2352 Stars
经典问题:二维偏序.给定平面中的n个点,求每个点左下方的点的个数. 因为 所有点已经以y为第一关键字,x为第二关键字排好序,所以我们按读入顺序处理,仅仅需要计算x坐标小于<=某个点的点有多少个就 ...
- 树状数组 二维偏序【洛谷P3431】 [POI2005]AUT-The Bus
P3431 [POI2005]AUT-The Bus Byte City 的街道形成了一个标准的棋盘网络 – 他们要么是北南走向要么就是西东走向. 北南走向的路口从 1 到 n编号, 西东走向的路从1 ...
- 洛谷 P1972 [SDOI2009]HH的项链-二维偏序+树状数组+读入挂(离线处理,思维,直接1~n一边插入一边查询),hahahahahahaha~
P1972 [SDOI2009]HH的项链 题目背景 无 题目描述 HH 有一串由各种漂亮的贝壳组成的项链.HH 相信不同的贝壳会带来好运,所以每次散步完后,他都会随意取出一段贝壳,思考它们所表达的含 ...
- Nowcoder farm ( 树状数组、二维前缀和、二维偏序 )
题目链接 分析 : 最简单的想法当然就是去模拟 直接对每个施肥料的操作进行模拟.然后计算贡献 但是这显然会超时.这题需要换一个思维 对于一个土地(也就是二维平面上的一个点)的种类是 T' 如果它被操作 ...
- cdq分治入门学习 cogs 1752 Mokia nwerc 2015-2016 G 二维偏序
/* CDQ分治的对象是时间. 即对于一个时间段[L, R],我们取mid = (L + R) / 2. 分治的每层只考虑mid之前的修改对mid之后的查询的贡献,然后递归到[L,mid],(mid, ...
随机推荐
- ES6核心,值得驻足花一天时间来学习
1.let 和 const 命令 在es5时,只有两种变量声明,var 和function.在es6中新增了四种let和const,以及另外两种声明import和class. 我们先讲解let和con ...
- 微信小程序rpx单位
rpx单位是微信小程序中css的尺寸单位,rpx可以根据屏幕宽度进行自适应.规定屏幕宽为750rpx.如在 iPhone6 上,屏幕宽度为375px,共有750个物理像素,则750rpx = 375p ...
- 设计模式之Adapter
设计模式总共有23种模式这仅仅是为了一个目的:解耦+解耦+解耦...(高内聚低耦合满足开闭原则) 介绍: 将两个不兼容的类纠合在一起使用,属于结构型模式,也有人称它为wrapper(包装类). 包装类 ...
- python并发编程之threading线程(一)
进程是系统进行资源分配最小单元,线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.进程在执行过程中拥有独立的内存单元,而多个线程共享内存等资源. 系列文章 py ...
- Linux下查看进程占用内存的最好方式
今天看到stackoverflow上关于linux下如何查看某个进程占用的内存是多少的回答,觉得非常棒,不过是全英文的,很多人可能看不懂,所以我翻译一下 翻译自http://stackoverflow ...
- 【读书笔记::深入理解linux内核】内存寻址
我对linux高端内存的错误理解都是从这篇文章得来的,这篇文章里讲的 物理地址 = 逻辑地址 – 0xC0000000:这是内核地址空间的地址转换关系. 这句话瞬间让我惊呆了,根据我的CPU的知识,开 ...
- 2017 ACM - ICPC Asia Ho Chi Minh City Regional Contest
2017 ACM - ICPC Asia Ho Chi Minh City Regional Contest A - Arranging Wine 题目描述:有\(R\)个红箱和\(W\)个白箱,将这 ...
- ThoughtWorks代码挑战——FizzBuzzWhizz游戏 通用高速版(C/C++ & C#)
最早看到这个题目是从@ 程序媛想事儿(Alexia) 的 最难面试的IT公司之ThoughtWorks代码挑战——FizzBuzzWhizz游戏 开始的,然后这几天陆陆续续有N个小伙伴发表了自己的文章 ...
- MySQL三种备份
一)备份分类 1 2 3 4 5 6 7 8 9 10 11 12 冷备:cold backup数据必须下线后备份 温备:warm backup全局施加共享锁,只能读,不能写 热备:hot backu ...
- Ubuntu每次开机后提示:检测到系统程序出现问题的解决方法
首先,错误报告存放位置: cd /var/crash/ ls //可以查看错误报告 1 2 sudo rm /var/crash/* //删除该目录下的所有文件 1 但是,这只是删除掉的是错误报告,如 ...