原文链接https://www.cnblogs.com/zhouzhendong/p/CF-Gym100543B.html

题目传送门 - CF-Gym100543B

题意

  给定一个折线图,对于每一条折线,问沿着这条折线往右看第一个看到的线段的编号(如果视线恰好看到上端点,则当没看见)

  放张图片助于理解:

  

  折线图用 $n$ 个点来描述。

  $n\leq 100000,\ \ \ \ 坐标范围:(x,y)|0\leq x,y\leq 10^9$

题解

  这题好妙啊。

  首先一个结论:如果射线与一段区间的点形成的上凸壳相交,那么他一定与这段区间内的折线段相交。

  我们只需要建个线段树,所有节点上建一个当前节点所表示的区间内的点构成的上凸壳,然后每次 $O(\log^2 n)$ 询问即可。

  如何 $O(\log^2 n)$ 询问?

  首先,线段树一只 $\log$ 。

  我们需要支持的是一只 $\log$ 判断射线是否与上凸壳相交。

  显然原线段与上凸壳的点的叉积是一个单峰函数。(根据叉积的定义,平行四边形的低不变,高为单峰函数,故面积也为单峰函数)

  于是显然可以三分搞定。

  但是被卡常数了。

  于是 foreverpiano 告诉了我一种巧妙的二分做法。

  (这里求叉积的点依次是线段左侧点,线段右侧点,当前点)

  对于每一次的 $mid$ ,我们看一看 原线段与凸壳上面的第 $mid$ 和 $mid+1$ 个点的叉积大小,分别记为 $v1$ 和 $v2$。

  如果 $v1>v2$ 则令 $R=mid-1$ 否则令 $L=mid+1$ 。

  注意一旦有 $v1>0$ 或者 $v2>0$ 就可以判断一定相交了。如果这个时候不return,则可能会有漏算。

  然后区间极小的时候暴力判。

  然后常数小了好多。

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=100005;
int T,n;
struct Point{
int x,y;
Point(){}
Point(int _x,int _y){
x=_x,y=_y;
}
}p[N],P[N];
vector <int> s[N<<3];
LL cross(Point a,Point b,Point c){
return 1LL*(b.x-a.x)*(c.y-a.y)-1LL*(c.x-a.x)*(b.y-a.y);
}
int read(){
char ch=getchar();
int x=0;
while (!isdigit(ch))
ch=getchar();
while (isdigit(ch))
x=(x<<1)+(x<<3)+ch-48,ch=getchar();
return x;
}
int st[N],top;
void Get_convex(vector <int> &s,int L,int R){
st[top=1]=R,st[++top]=R-1;
for (int i=R-2;i>=L;i--){
while (top>1&&cross(p[st[top-1]],p[st[top]],p[i])<=0)
top--;
st[++top]=i;
}
s.clear();
for (int i=top;i>0;i--)
s.push_back(st[i]);
}
void build(int rt,int L,int R){
if (L==R){
s[rt].clear();
s[rt].push_back(L);
return;
}
Get_convex(s[rt],L,R);
int mid=(L+R)>>1,ls=rt<<1,rs=ls|1;
build(ls,L,mid);
build(rs,mid+1,R);
}
int Query(Point a,Point b,vector <int> &s){
int L=0,R=s.size()-1,mid;
while (L+3<=R){
mid=(L+R)>>1;
LL x=cross(a,b,p[s[mid]]),y=cross(a,b,p[s[mid+1]]);
if (x>0||y>0)
return 1;
if (x>y)
R=mid-1;
else
L=mid+1;
}
int now=-1;
for (int i=L;i<=R;i++)
if (cross(a,b,p[s[i]])>0)
return 1;
return 0;
}
int Query(int rt,int L,int R,int xL,int xR){
if (xL>xR||L>xR||R<xL||!Query(p[xL-2],p[xL-1],s[rt]))
return 0;
if (L==R)
return L-1;
int mid=(L+R)>>1,ls=rt<<1,rs=ls|1;
int now=Query(ls,L,mid,xL,xR);
return now?now:Query(rs,mid+1,R,xL,xR);
}
int main(){
T=read();
while (T--){
n=read();
for (int i=1;i<=n;i++)
p[i].x=read(),p[i].y=read();
build(1,1,n);
for (int i=1;i<n;i++){
cout << Query(1,1,n,i+2,n);
if (i<n-1)
putchar(' ');
}
puts("");
}
return 0;
}

  

Codeforces Gym100543B 计算几何 凸包 线段树 二分/三分 卡常的更多相关文章

  1. Codeforces Gym 100231B Intervals 线段树+二分+贪心

    Intervals 题目连接: http://codeforces.com/gym/100231/attachments Description 给你n个区间,告诉你每个区间内都有ci个数 然后你需要 ...

  2. Codeforces 431E Chemistry Experiment 线段树 + 二分

    Chemistry Experiment 维护一个权值线段树,然后二分答案. #include<bits/stdc++.h> #define LL long long #define LD ...

  3. Codeforces Gym 100803G Flipping Parentheses 线段树+二分

    Flipping Parentheses 题目连接: http://codeforces.com/gym/100803/attachments Description A string consist ...

  4. Educational Codeforces Round 64 (Rated for Div. 2) (线段树二分)

    题目:http://codeforces.com/contest/1156/problem/E 题意:给你1-n  n个数,然后求有多少个区间[l,r] 满足    a[l]+a[r]=max([l, ...

  5. Buses and People CodeForces 160E 三维偏序+线段树

    Buses and People CodeForces 160E 三维偏序+线段树 题意 给定 N 个三元组 (a,b,c),现有 M 个询问,每个询问给定一个三元组 (a',b',c'),求满足 a ...

  6. [Codeforces 1197E]Culture Code(线段树优化建图+DAG上最短路)

    [Codeforces 1197E]Culture Code(线段树优化建图+DAG上最短路) 题面 有n个空心物品,每个物品有外部体积\(out_i\)和内部体积\(in_i\),如果\(in_i& ...

  7. hdu4614 线段树+二分 插花

    Alice is so popular that she can receive many flowers everyday. She has N vases numbered from 0 to N ...

  8. 洛谷P4344 脑洞治疗仪 [SHOI2015] 线段树+二分答案/分块

    !!!一道巨恶心的数据结构题,做完当场爆炸:) 首先,如果你用位运算的时候不小心<<打成>>了,你就可以像我一样陷入疯狂的死循环改半个小时 然后,如果你改出来之后忘记把陷入死循 ...

  9. LOJ2401 JOISC2017 Dragon2 计算几何、线段树

    传送门 先考虑每一个攻击方的龙和被攻击方的龙可以与多少个被攻击方/攻击方的龙匹配. 对于攻击方的龙\(A\)和被攻击方的龙\(B\),在道路为线段\((C,D)\)的情况下,能够与下图位置的所有对应属 ...

随机推荐

  1. Android 代码混淆 混淆方案

    本篇文章:自己在混淆的时候整理出比较全面的混淆方法,比较实用,自己走过的坑,淌出来的路.请大家不要再走回头路,可能只要我们代码加混淆,一点不对就会导致项目运行崩溃等后果,有许多人发现没有打包运行好好地 ...

  2. C语言学习及应用笔记之一:C运算符优先级及使用问题

    C语言中的运算符绝对是C语言学习和使用的一个难点,因为在2011版的标准中,C语言的运算符的数量超过40个,甚至比关键字的数量还要多.这些运算符有单目运算符.双目运算符以及三目运算符,又涉及到左结合和 ...

  3. Oracle 闪回

    Oracle 闪回特性(FLASHBACK DATABASE) 本文来源于:gerainly 的<Oracle 闪回特性(FLASHBACK DATABASE) > -========== ...

  4. Confluence 6 SQL Server 创建一个数据库和数据库用户

    一旦你成功安装了 SQL Server 服务器,请按照下面的方法为你的 Confluence 创建数据库用户和数据库: 使用你的 SQL 管理员权限,创建一个新的数据库(例如 confluence). ...

  5. windows下如何安装pip以及如何查看pip是否已经安装成功

    最近刚学习python,发现很多关于安装以及查看pip是否安装成的例子都比较老,不太适合于现在(python 3.6 )因此,下一个入门级别的教程. 0:首先如何安装python我就不做介绍了. 1: ...

  6. NIO(五)

    分散读取,聚集写入 package com.cppdy.nio; import java.io.RandomAccessFile; import java.nio.ByteBuffer; import ...

  7. ajax--参数默认值问题

    注:通过参数默认值,能让参数映射更加灵活,有些参数可以不必传递,如果传递则 覆盖默认.并且永远都是后面的覆盖前面的内容 通过$.extend合并对象 语法1: var newobj= $.extend ...

  8. 如何在EXCEL中找出第一列中不包含的第二列数据

    1.找出第一列中不包含的第二列数据:=IFERROR(VLOOKUP(A:A,B:B,1,0),"无") 2.A列相同,B列相加:=SUMIF(G:G,G1,J:J)

  9. spring cloud 路由网关zuul基本使用

    在微服务架构中,需要几个关键的组件,服务注册与发现.服务消费.负载均衡.断路器.智能路由.配置管理等,由这几个组件可以组建一个简单的微服务架构.客户端的请求首先经过负载均衡(zuul.Ngnix),再 ...

  10. 用 DocumentFormat.OpenXml 和Microsoft.Office.Interop.Word 写入或者读取word文件

    using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Tex ...