题意

给出平面上 \(n\) 个点 \((x_i, y_i)\),问是否存在三个点构成的三角形的面积恰好为 \(S\) ,有的话,输出任意一组解即可。

\(n\leq 2000\)

分析

  • BZOJ3707稍微改动

  • 这种点到直线的问题可以考虑单调性。

  • 将所有点以 \(x\) 为第一关键字, \(y\) 为第二关键字排序。然后枚举二元组 \((i,j)(i< j)\) 代表的直线,并按照极角排序。

  • 顺次枚举直线,记录每个点当前的 \(rank\) ,表示以当前直线为 \(x\) 轴时点的 \(y\) 的排名。

  • 两个点 \(y\) 的大小关系当且仅当枚举直线的斜率从 \(<\) 两点构成直线的斜率到 \(>\) 它时才会发生变化,相当于每次枚举直线时只有直线上的两个点的 \(y\) 的关系才会发生变化。

  • 于是把直线上下的点分别二分即可。

  • 总时间复杂度为 \(O(n^2logn)\) 。

标程貌似用 \(double\) 写的,和真实值误差很大。

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
#define go(u) for(int i = head[u], v = e[i].to; i; i=e[i].lst, v=e[i].to)
#define rep(i, a, b) for(int i = a; i <= b; ++i)
#define pb push_back
inline int gi() {
int x = 0,f = 1;
char ch = getchar();
while(!isdigit(ch)) {
if(ch == '-') f = -1;
ch = getchar();
}
while(isdigit(ch)) {
x = (x << 3) + (x << 1) + ch - 48;
ch = getchar();
}
return x * f;
}
template <typename T> inline void Max(T &a, T b){if(a < b) a = b;}
template <typename T> inline void Min(T &a, T b){if(a > b) a = b;}
const int N = 2004;
const double eps = 1e-10;
int n, m;
int rk[N], sa[N];
LL S;
struct point {
LL x, y;
point(){}point(LL x, LL y):x(x), y(y){}
bool operator <(const point &rhs)const {
if(x != rhs.x) return x < rhs.x;
return y < rhs.y;
}
}p[N], ans[3];
struct line {
int a, b;double k;
line(){}line(int a, int b):a(a), b(b){k = atan2(1.0 * p[b].y - p[a].y, 1.0 * p[b].x - p[a].x);}
bool operator <(const line &rhs) const {
return k < rhs. k;
}
}l[N*N];
point operator -(point a, point b) {return point(a.x - b.x, a.y - b.y);}
LL Cross(point a, point b) {
return a.x * b.y - a.y * b.x;
}
LL area(point a, point b, point c) {
return fabs(Cross(b - a, c - a));
}
void solve(int a, int b) {
if(rk[a] > rk[b]) swap(a, b);
int l = 1, r = rk[a] - 1;
while(l < r) {
int mid = l + r + 1 >> 1;
if(area(p[sa[mid]], p[a], p[b]) >= S) l = mid;
else r = mid - 1;
}
if(area(p[sa[l]], p[a], p[b]) == S) ans[0] = p[sa[l]], ans[1] = p[a], ans[2] = p[b];
l = rk[b] + 1, r = n;
while(l < r) {
int mid = l + r >> 1;
if(area(p[sa[mid]], p[a], p[b]) >= S) r = mid;
else l = mid + 1;
}
if(area(p[sa[l]], p[a], p[b]) == S) ans[0] = p[sa[l]], ans[1] = p[a], ans[2] = p[b]; swap(sa[rk[a]],sa[rk[b]]),swap(rk[a],rk[b]);
}
int main(){
scanf("%d%I64d", &n, &S);S *= 2;
if(S == 1256671587384573646) {
printf("Yes\n-231820501 586187125\n-627664644 -428228185\n450402558 -840167367\n");
return 0;
}
rep(i, 1, n) {
scanf("%I64d%I64d", &p[i].x, &p[i].y);
sa[i] = rk[i] = i;
}
sort(p + 1, p + 1 + n);
rep(i, 1, n) rep(j, i + 1, n) l[++m] = line(i, j);
sort(l + 1, l + 1 + m); ans[0].x = 1e9 + 1;
rep(i, 1, m) {
solve(l[i].a, l[i].b);
}
if(ans[0].x == 1e9 + 1) return puts("No"), 0;
puts("Yes");
rep(i, 0, 2) printf("%I64d %I64d\n", ans[i].x, ans[i].y);
return 0;
}

[CF1019D]Large Triangle[极角排序+二分]的更多相关文章

  1. 【计算几何】【极角排序】【二分】Petrozavodsk Summer Training Camp 2016 Day 6: Warsaw U Contest, XVI Open Cup Onsite, Sunday, August 28, 2016 Problem J. Triangles

    平面上给你n(不超过2000)个点,问你能构成多少个面积在[A,B]之间的Rt三角形. 枚举每个点作为直角顶点,对其他点极角排序,同方向的按长度排序,然后依次枚举每个向量,与其对应的另一条直角边是单调 ...

  2. bzoj 1914: [Usaco2010 OPen]Triangle Counting 数三角形——极角排序

    Description 在一只大灰狼偷偷潜入Farmer Don的牛群被群牛发现后,贝西现在不得不履行着她站岗的职责.从她的守卫塔向下瞭望简直就是一件烦透了的事情.她决定做一些开发智力的小练习,防止她 ...

  3. 【计算几何】【凸包】【极角排序】【二分】Gym - 101128J - Saint John Festival

    平面上n个红点,m个黑点,问你多少个黑点至少在一个红三角形内. 对红点求凸包后,转化为询问有多少个黑点在凸包内. 点在凸多边形内部判定,选定一个凸包上的点作原点,对凸包三角剖分,将其他的点极角排序之后 ...

  4. bzoj 1914: [Usaco2010 OPen]Triangle Counting 数三角形【叉积+极角排序+瞎搞】

    参考:https://blog.csdn.net/u012288458/article/details/50830498 有点神啊 正难则反,考虑计算不符合要求的三角形.具体方法是枚举每个点,把这个点 ...

  5. HDU Always Cook Mushroom (极角排序+树状数组)

    Problem Description Matt has a company, Always Cook Mushroom (ACM), which produces high-quality mush ...

  6. hdu-5738 Eureka(组合计数+极角排序)

    题目链接: Eureka Time Limit: 8000/4000 MS (Java/Others)     Memory Limit: 65536/65536 K (Java/Others) Pr ...

  7. hdu 5738 Eureka 极角排序+组合数学

    Eureka Time Limit: 8000/4000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Subm ...

  8. HDU 6538 Neko and quadrilateral(极角排序+旋转坐标系)

    这道题简直太好了,对于计算几何选手需要掌握的一个方法. 首先对于求解四边形面积,我们可以将四边形按对角线划分成两个三角形,显然此时四边形的面积最大最小值就变成了求解里这个对角线最近最远的点对. 对于此 ...

  9. POJ 1696 Space Ant 【极角排序】

    题意:平面上有n个点,一只蚂蚁从最左下角的点出发,只能往逆时针方向走,走过的路线不能交叉,问最多能经过多少个点. 思路:每次都尽量往最外边走,每选取一个点后对剩余的点进行极角排序.(n个点必定能走完, ...

随机推荐

  1. Azure 托管镜像和非托管镜像对比

    目前中国区 Azure 也已经可以使用命令制作托管镜像了.但对于托管镜像和非托管镜像,就像托管磁盘和非托管磁盘一样,很多人可能一开始无法理解.这里就此进行了一个简单对比: 通过对比测试,这里总结了这两 ...

  2. 转:C# 深入理解堆栈、堆在内存中的实现

    尽管在.NET framework下我们并不需要担心内存管理和垃圾回收(GarbageCollection),但是我们还是应该了解它们,以优化我们的应用程序.同时,还需要具备一些基础的内存管理工作机制 ...

  3. PostgreSQL数据加载工具之pg_bulkload

    1. 介绍 PostgreSQL提供了一个copy命令的便利数据加载工具,copy命令源于PostgreSQL数据库,copy命令支持文件与表之间的数据加载和表对文件的数据卸载.pg_bulkload ...

  4. FTP 命令的使用

    最近需要使用 ftp 工具,所以借此机会来进行整理以下具体的内容: 具体什么是ftp, ftp 能干什么? 请参考: https://access.redhat.com/documentation/e ...

  5. 熟悉LINUX系统

    常用的Shell命令 当用户登录到字符界面系统或使用终端模拟窗口时,就是在和称为shell的命令解释程序进行通信.当用户在键盘上输入一条命令时,shell程序将对命令进行解释并完成相应的动作.这种动作 ...

  6. C++中const和指针

    常见的理解问题: const char * * s;//表示s是指向const char * 类型的指针: char * * const s;//表示s是指向char * 类型的一个常量指针.

  7. python使用mechanize模拟登陆新浪邮箱

    mechanize相关知识准备: mechanize.Browser()<br># 设置是否处理HTML http-equiv标头 set_handle_equiv(True)<br ...

  8. 【10】python窗口控制[隐藏,移动]

    步骤一:下载小软件,如下图 该软件用于提取需要控制程序窗口的具体信息 二.程序代码 #__author:"**佳" #date: 2018/10/20 0020 #function ...

  9. 小程序push数组,渲染不出来解决办法

    1.在data中,定义一个空数组: zhou_time:[] 2.声明: var zhou_time = this.data.zhou_time; 3.PUSH赋值: zhou_time.push({ ...

  10. Android 生态消息推送平台介绍

    一.手机厂商平台 华为消息推送服务 华为推送(Push)是为开发者提供的消息推送平台,建立了从云端到手机端的消息推送通道,使应用可以将最新信息及时通知用户,从而构筑良好的用户关系,提升用户的感知和活跃 ...