Description

  

  现在在平面上给你一条折线 \(P_1P_2 \cdots P_n\) 。 \(x\) 坐标是严格单调递增的。对于每一段折线 \(P_iP_{i+1}\) ,请你找一个最小的 \(j\) ,使得 \(j \gt i\) 且CJB走在 \(P_iP_{i+1}\) 上能看到折线 \(P_jP_{j+1}\) 的任何一个点。注意,CJB的高度无限趋于0但不可忽略。也就是说,请找一条编号最小的折线 \(P_jP_{j+1}\) 使得 \(j \gt i\) 且线段 \(P_jP_{j+1}\)相交。

   

   

  

Solution

  

  首先手玩。

  

  考虑每一条射线\(\alpha=(P_i,P_{i+1})\)的答案,其实就是最小的\(j\),满足\(j>i\)且\(P_{j+1}\)严格在该射线上方。

  

  有效的、需要考虑的\(P_{j+1}\),一定在由\((i,n]\)这些点构成的凸包上。我们相当于要判定一条射线\(\alpha\)与凸包是否有交,并找到交线的具体位置。

  第一个问题很好解决,二分凸包上最逼近射线\(\alpha\)斜率的点,若其在射线上方则凸包与射线有交,否则直接无解。

  

  关键是第二个问题。我们知道射线与凸包有交,甚至可以知道具体是哪一条凸包边与射线相交,却不知道是哪一条原边与射线有交,无法输出答案。我们发现这个凸包的信息已经不足以解决我们的问题了,但我们可以二分继续做:如果按相同方法判定左凸包也与射线有交,那么显然答案在左边,递归左凸包计算,并返回其的答案;否则,只能到右凸包里寻找答案。

  

  单次询问复杂度\(\mathcal O(log^2)\)。

  

  关键思路是无法确定具体方案的时候,考虑利用存在性二分答案。另一个Tips是有关线段树的二分问题,不要总想着用二分套线段树,而应该想想能否用线段树上二分,后者一般是两个\(log\),而前者是三个\(log\)。

  

  

  

Code

  

#include <cstdio>
#include <vector>
#define pb push_back
using namespace std;
namespace IO{
const int S=10000005;
char buffer[S];
int pos;
void Load(){
pos=0;
fread(buffer,1,S,stdin);
}
char getChar(){
return buffer[pos++];
}
int getInt(){
int x=0,f=1;
char c=getChar();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getChar();}
while('0'<=c&&c<='9'){x=x*10+c-'0';c=getChar();}
return x*f;
}
}
using IO::getInt;
const int N=100005;
const double EPS=1e-6;
typedef long long ll;
typedef vector<int> vi;
int n;
struct Dot{ int x,y; }a[N];
bool slope_dec(int i,int j,int k){
return 1ll*(a[j].y-a[i].y)*(a[k].x-a[j].x)>1ll*(a[j].x-a[i].x)*(a[k].y-a[j].y);
}
double slope(int i,int j){
return 1.0*(a[j].y-a[i].y)/(a[j].x-a[i].x);
}
void getline(int i,int j,double &k,double &b){
k=slope(i,j);
b=a[i].y-k*a[i].x;
}
namespace SEG{
const int S=N*2;
int rt,sz;
int ch[S][2];
vi hull[S];
int top[S];
double k,b;
void build(int &u,int l,int r){
u=++sz;
hull[u]=vi(r-l+2);
top[u]=0;
for(int i=l;i<=r+1;i++){
while(top[u]>=2&&!slope_dec(hull[u][top[u]-2],hull[u][top[u]-1],i))
top[u]--;
hull[u][top[u]++]=i;
}
hull[u].resize(top[u]);
if(l==r)
return;
int mid=(l+r)>>1;
build(ch[u][0],l,mid);
build(ch[u][1],mid+1,r);
}
void set(double _k,double _b){
k=_k;
b=_b;
}
int find(int u){
int l=0,r=top[u]-2,mid;
while(l<=r){
int mid=(l+r)>>1;
if(slope(hull[u][mid],hull[u][mid+1])>k)
l=mid+1;
else
r=mid-1;
}
int who=hull[u][r+1];
return (k*a[who].x+b+EPS<=a[who].y)?who-1:0;
}
int query(int u,int l,int r,int L,int R){
int mid=(l+r)>>1;
if(L<=l&&r<=R){
if(l==r)
return find(u);
if(!find(u))
return 0;
if(find(ch[u][0]))
return query(ch[u][0],l,mid,L,R);
else
return query(ch[u][1],mid+1,r,L,R);
}
if(R<=mid)
return query(ch[u][0],l,mid,L,R);
else if(mid<L)
return query(ch[u][1],mid+1,r,L,R);
else{
int left=query(ch[u][0],l,mid,L,mid);
if(left)
return left;
return query(ch[u][1],mid+1,r,mid+1,R);
}
}
}
void readData(){
n=getInt();
for(int i=1;i<=n;i++)
a[i].x=getInt(), a[i].y=getInt();
}
void solve(){
for(int i=1;i<n;i++)
if(i<=n-2){
double k,b;
getline(i,i+1,k,b);
SEG::set(k,b);
printf("%d ",SEG::query(SEG::rt,1,n-1,i+1,n-1));
}
else
printf("0 ");
puts("");
}
int main(){
IO::Load();
readData();
SEG::build(SEG::rt,1,n-1);
solve();
return 0;
}

Mountainous landscape的更多相关文章

  1. BZOJ4049 [Cerc2014] Mountainous landscape

    首先对于一个给定的图形,要找到是否存在答案非常简单... 只要维护当然图形的凸包,看一下是否有线段在这条直线上方,直接二分即可,单次询问的时间复杂度$O(logn)$ 现在用线段树维护凸包,即对于一个 ...

  2. bzoj AC倒序

    Search GO 说明:输入题号直接进入相应题目,如需搜索含数字的题目,请在关键词前加单引号 Problem ID Title Source AC Submit Y 1000 A+B Problem ...

  3. NOIp2018模拟赛三十五

    两道大数据结构把我砸懵 成绩:未提交 Orz xfz两道正解 A:[BZOJ4049][CREC2014B]mountainous landscape B:CJB的大作(CF改编题)

  4. SAP SLT (Landscape Transformation) 企业定制培训

    No. Item Remark 1 SAP SLT概述 SAP Landscape Transformation Overview 2 SAP SLT 安装与配置<1> for abap ...

  5. iPad apple-touch-startup-image实现portrait和landscape

    iPad apple-touch-startup-image实现portrait和landscape 为ipad制作web应用程序的启动画面时发现个问题,只能显示竖屏图,横屏图出不来,网上的朋友都说无 ...

  6. JS 获取和监听屏幕方向变化(portrait / landscape)

    移动设备的屏幕有两个方向: landscape(横屏)和portrait(竖屏),在某些情况下需要获取设备的屏幕方向和监听屏幕方向的变化,因此可以使用Javascript提供的 MediaQueryL ...

  7. [JS代码]如何判断ipad或者iphone是否为横屏或者竖屏 - portrait或者landscape

    //判断横屏或者竖屏 function orient() { //alert('gete'); if (window.orientation == 0 || window.orientation == ...

  8. iOS的横屏(Landscape)与竖屏(Portrait)InterfaceOrientation

    http://www.molotang.com/articles/1530.html 接着上篇写的触摸事件,这次借机会整理下iOS横屏和竖屏的翻转方向支持,即InterfaceOrientation相 ...

  9. CNCF CloudNative Landscape

    cncf landscape CNCF Cloud Native Interactive Landscape 1. App Definition and Development 1. Database ...

随机推荐

  1. 20155223 Exp2 后门原理与实践

    20155223 Exp2 后门原理与实践 实验预热 一.windows获取Linux shell Windows:使用 ipconfig 命令查看当前机器IP地址. 进入ncat所在文件地址,输入命 ...

  2. python基础学习1-流程控制和判断

    python for循环和 if流程控制用法 Ages=22 for i in range(10): inputAges = int(input("输入年龄")) if input ...

  3. Spring Boot (十五): Spring Boot + Jpa + Thymeleaf 增删改查示例

    这篇文章介绍如何使用 Jpa 和 Thymeleaf 做一个增删改查的示例. 先和大家聊聊我为什么喜欢写这种脚手架的项目,在我学习一门新技术的时候,总是想快速的搭建起一个 Demo 来试试它的效果,越 ...

  4. 微信小程序初体验与DEMO分享

    前言 前一段时间微信公布小程序,瞬间引来了大量的关注.博主的公司也将其定为目标之一,遂派本菜为先头兵(踩坑侠). 这次开发了一个比较完整的DEMO,模仿自某个APP首页,由于保护隐私的目的我把数据拷贝 ...

  5. 每日scrum(4)

    今天是冲刺第4天,大家都忙着找大二的学弟学妹来点评来支持我们的软件. 遇到的问题主要是如何劝说学弟学妹选择我们的软件然后继续往下做. 任务看板: 燃尽图:

  6. 【python】自学笔记

    参考文献 1.环境安装 1.1 python 工作环境 2.7.14 1.2 pycharm community2018.1.1 4 x64 2.第一行代码 2.1 python交互模式, >& ...

  7. CMS垃圾收集器与G1收集器

    1.CMS收集器 CMS收集器是一种以获取最短回收停顿时间为目标的收集器.基于“标记-清除”算法实现,它的运作过程如下: 1)初始标记 2)并发标记 3)重新标记 4)并发清除 初始标记.从新标记这两 ...

  8. 三星a9上测试egret与pixi.js的渲染性能

    for (let i = 0; i < 500; i++) { let shape = new egret.Shape(); shape.graphics.beginFill(0xff0000) ...

  9. mac 关闭显示器 & 快捷键

    mac 关闭显示器 & 快捷键 https://support.apple.com/zh-cn/HT201236 https://support.apple.com/zh-cn/HT20705 ...

  10. 洛谷P13445 [USACO5.4]奶牛的电信Telecowmunication(网络流)

    题目描述 农夫约翰的奶牛们喜欢通过电邮保持联系,于是她们建立了一个奶牛电脑网络,以便互相交流.这些机器用如下的方式发送电邮:如果存在一个由c台电脑组成的序列a1,a2,...,a(c),且a1与a2相 ...