因为只有std,没有自我实现,所以是无码专区

主要是为了训练思维能力

solution才是dls正解,但是因为只有潦草几句,所以大部分会有我自己基于正解上面的算法实现过程,可能选择的算法跟std中dls的实现不太一样。

std可能也会带有博主自己的注释。


problem

平面上有 nnn 个点,(xi,yi)(x_i,y_i)(xi​,yi​)。

qqq 次询问,每次给定三个点 A(x+d,y),B(x,y),C(x,y+d)A(x+d,y),B(x,y),C(x,y+d)A(x+d,y),B(x,y),C(x,y+d)。

求有多少个点 (xi,yi)(x_i,y_i)(xi​,yi​) 在这个三角形内部或边界上。

10s,128MB,all≤1e610s,128MB,all\le 1e610s,128MB,all≤1e6。


my idea

给定的三角新很有特点:是等腰直角三角形且直角边分别与一条坐标轴平行。

并不是任意的一个三角形。那么这个三角形最难处理的自然就是斜边部分,因为不与坐标轴平行。

如果这是个正方形,就是个很简单的二维差分数点问题。

我曾试图用所有的点减去没有落在指定区域的点,但是发现外围图形仍然会被切割成若干个矩形和一个三角形,还是不会计算三角形。❌

我曾试图计算一个点的位置会被多少个三角形覆盖,对这些三角形贡献 111。但是查询的三角形压根不能找到一种范围限制能够说明:横纵坐标简单的加减为某个范围时属于这个三角形。❌

这两种思路都卡在了三角形重叠部分,更具体而言是没有找到要贡献的点坐标的特征性,显然这应该是正解的思路,这导致我们只能尝试不是正解的想法看能否优化跑过。

既然题目给的是平行坐标轴的直角三角形,那么这个直角边一定是切入点。

三角形不好做,但是四边形好做。

将三角形划分成一个四边形,和两个三角形。

如图:一个三角形存在很多种切割方式。

四边形是很容易计算的,三角形就递归地切割。所以时间复杂度是跟这个三角形切割挂钩的。

出于平衡左右时间的思想,我们肯定会选取“正半分”,使得两个三角形“完全一样”。

【但是如果只计算整点,“正半分”可能是分数,所以是尽可能地“正半分”,让两边地效率尽可能平衡。】

这种递归思想就是——分治。

没错,我们可以采取分而治之的做法,递归求解计算。

最底层的出口就是直角边某一条长度为 111 的三角形,统计另一条边的贡献即可。

这样,划分最多 logloglog 层。

四边形的计算由于 N×MN\times MN×M 根本开不下,无法预处理然后 O(1)O(1)O(1) 差分求解。

只能采取数据结构计算。

具体而言:

将 nnn 个点按 xxx 第一关键字,yyy 第二关键字排序。

需要在划分的一个区间内查询一个区间的问题。又是它!——主席树。

以 yyy 建立线段树,第 iii 个版本维护的是前 iii 个点的主席数信息,权值线段树。

线段树上节点维护 y∈[l,r]y\in[l,r]y∈[l,r] 的点有多少个。

i→i+1i\rightarrow i+1i→i+1,单点更新 yiy_iyi​。

查询 (x1,y1,x2,y2)(x1,y1,x2,y2)(x1,y1,x2,y2)。找到 x1<xlx1<x_lx1<xl​ 的最小 lll,以及 xr<x2xr<x2xr<x2 的最大 rrr。二分查找。

然后就询问 l∼rl\sim rl∼r 版本中 [y1,y2][y1,y2][y1,y2] 内点的个数。

这样来看数据结构自带两个 logloglog,外层还有一个。时间复杂度是 O(nlog3n)O(nlog^3n)O(nlog3n) 的。

只能堪堪通过 70%70\%70% 的数据点 2×1052\times 10^52×105。

【计算出来大概是 8e88e88e8 的,10s10s10s 跑 1e91e91e9,常数小写得好看应该是能跑过的。】

考虑优化,优化掉二分查找的 logloglog。

最开始排序的 logloglog 省不了。

对于 iii,直接二分找 l,rl,rl,r 记录下来 Li,RiL_i,R_iLi​,Ri​。

这样是将里面嵌套的 logloglog 放在了外面。

O(nlog⁡3n)→O(nlog⁡2n+nlog⁡n)O(n\log^3n)\rightarrow O(n\log^2n+n\log n)O(nlog3n)→O(nlog2n+nlogn)。

就是两个 logloglog 的了。

算出来 4e84e84e8,相对与 1e91e91e9 而言应该是绰绰有余的,常数大点应该没关系。

trick:图上一条线段分裂,但实际上计算的时候并不重叠。

中间界可以划给三角形部分,也可以是矩形部分。

但具体实现会发现,将中间界划分给三角形会比较好算,因为是封闭的。

不好说明,给图直观感受。

但是也不是说不能写,应该也是能实现的。


solution

直接查询,就是三维数点问题。CDQCDQCDQ 分治做 O(nlog⁡2n)O(n\log^2n)O(nlog2n)。

又来了,一句话一页阐释。

为什么是三维数点??怎么数??


扩展:如何用三角形的三个坐标表示三角形中任意一点的坐标。

假设三角形三点分别为 A(x1,y1),B(x2,y2),C(x3,y3)A(x1,y1),B(x2,y2),C(x3,y3)A(x1,y1),B(x2,y2),C(x3,y3),现要表示内部点 O(x,y)O(x,y)O(x,y)。

设射线 AOAOAO 交 BCBCBC 与点 DDD,AO⃗=mAD⃗,BD⃗=nBC⃗\vec{AO}=m\vec{AD},\vec{BD}=n\vec{BC}AO=mAD,BD=nBC。

则 AO⃗=mAD⃗=m(AB⃗+BD⃗)=mAB⃗+mnBC⃗\vec{AO}=m\vec{AD}=m(\vec{AB}+\vec{BD})=m\vec{AB}+mn\vec{BC}AO=mAD=m(AB+BD)=mAB+mnBC。

即:
(x−x1,y−y1)=m(x2−x1,y2−y1)+mn(x3−x2,y3−y2)(x-x1,y-y1)=m(x2-x1,y2-y1)+mn(x3-x2,y3-y2) (x−x1,y−y1)=m(x2−x1,y2−y1)+mn(x3−x2,y3−y2)

=(m(x2−x1)+mn(x3−x2),m(y2−y1)+mn(y3−y2))=(m(x2-x1)+mn(x3-x2),m(y2-y1)+mn(y3-y2)) =(m(x2−x1)+mn(x3−x2),m(y2−y1)+mn(y3−y2))

⇒{x−x1=m(x2−x1)+mn(x3−x2)⇒x=x1(1−m)+x2(m−mn)+x3mny−y1=m(y2−y1)+mn(y3−y2)⇒y=y1(1−m)+y2(m−mn)+y3mn\Rightarrow\begin{cases}x-x1=m(x2-x1)+mn(x3-x2)\Rightarrow x=x1(1-m)+x2(m-mn)+x3mn\\y-y1=m(y2-y1)+mn(y3-y2)\Rightarrow y=y1(1-m)+y2(m-mn)+y3mn\\\end{cases} ⇒{x−x1=m(x2−x1)+mn(x3−x2)⇒x=x1(1−m)+x2(m−mn)+x3mny−y1=m(y2−y1)+mn(y3−y2)⇒y=y1(1−m)+y2(m−mn)+y3mn​

换元表示 a=1−m,b=m−mna=1-m,b=m-mna=1−m,b=m−mn ,则
{x=a⋅x1+b⋅x2+(1−a−b)x3y=a⋅y1+b⋅y2+(1−a−b)y3\begin{cases}x=a·x1+b·x2+(1-a-b)x3\\y=a·y1+b·y2+(1-a-b)y3\\\end{cases} {x=a⋅x1+b⋅x2+(1−a−b)x3y=a⋅y1+b⋅y2+(1−a−b)y3​

dbq,我确实没看懂这个三维数点怎么做。

观察性质,三角形区域 (x′,y′)−(x′+d,y′)−(x′,y′+d)(x',y')-(x'+d,y')-(x',y'+d)(x′,y′)−(x′+d,y′)−(x′,y′+d)。
相当于总区域减去 x<x′,y<y′,x+y>x′+y′+dx<x',y<y',x+y>x'+y'+dx<x′,y<y′,x+y>x′+y′+d 三个半平面。
然后补上三个被减了两次的区域。
即 x<x′∧y<y′,x<x′∧x+y>x′+y′+d′,y<y′∧x+y>x′+y′+dx<x'\wedge y<y',x<x'\wedge x+y>x'+y'+d',y<y'\wedge x+y>x'+y'+dx<x′∧y<y′,x<x′∧x+y>x′+y′+d′,y<y′∧x+y>x′+y′+d。

这三个部分都是二维数点,直接做,时间复杂度 O(nlog⁡n)O(n\log n)O(nlogn)。

其实看题解的时候我并不懂,但是一看代码就懂了!!

原来是我不会等腰直角三角形的二维数点!!其实很简单。


code

#include <bits/stdc++.h>
using namespace std;
#define FOR(a,b,c) for (int a=b,_c=c;a<=_c;a++)
#define FORD(a,b,c) for (int a=b;a>=c;a--)
#define REP(i,a) for(int i=0,_a=(a); i<_a; ++i)
#define REPD(i,a) for(int i=(a)-1; i>=0; --i)
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define sz(a) int(a.size())
#define reset(a,b) memset(a,b,sizeof(a))
#define oo 1000000007using namespace std;typedef long long ll;
typedef pair<int, int> pii;const int maxn = 1000007;
const int maxv = 1000007;int n, q, BIT[maxn], ans[maxn];
struct node {int x, y, d, id;
} a[maxn * 2];bool cmp1(const node &a, const node &b) {return a.y < b.y || (a.y == b.y && a.id > b.id);
}bool cmp2(const node &a, const node &b) {int v1 = a.x + a.y + a.d;int v2 = b.x + b.y + b.d;return v1 < v2 || (v1 == v2 && a.id < b.id);
}void update(int p) {for (int i = p; i <= maxv; i += i & (-i))BIT[i]++;
}int get(int p) {int ans = 0;p = min(p, maxv);for (int i = p; i; i -= i & (-i))ans += BIT[i];return ans;
}int main() {freopen("triangular.in", "r", stdin);freopen("triangular.out", "w", stdout);scanf("%d%d", &n, &q);FOR(i, 1, n) {scanf("%d%d", &a[i].x, &a[i].y);a[i].id = 0;}FOR(i, 1, q) {scanf("%d%d%d", &a[i + n].x, &a[i + n].y, &a[i + n].d);a[i + n].id = i;}sort(a + 1, a + n + q + 1, cmp1);FOR(i, 1, n + q)if (a[i].id)ans[a[i].id] -= get(a[i].x + a[i].d) - get(a[i].x - 1);elseupdate(a[i].x);sort(a + 1, a + n + q + 1, cmp2);reset(BIT, 0);FOR(i, 1, n + q)if (a[i].id)ans[a[i].id] += get(a[i].x + a[i].d) - get(a[i].x - 1);elseupdate(a[i].x);FOR(i, 1, q) printf("%d\n", ans[i]);return 0;
}

总结

这道题大概断断续续想了两天(每天 40min40min40min 左右)吧,当我突然意识到分拆递归处理的时候,后面的进展就比较快了。

其实std的做法是很有局限性的,必须充分利用等腰直角,直角边平行于坐标轴三个条件,但也是挺妙的。

但是我的想法是可以扔掉等腰这个条件的,只需要直角三角形,直角边平行于坐标轴就可以了,但是多了个 logloglog。

当然这也是我的想法,我也不知道是否正确,欢迎友好讨论以及分享不同思路。

【无码专区8】三角形二维数点——计数有多少个给定点落在三角形区域内相关推荐

  1. 【无码专区13】最小公倍数(线段树)

    因为只有std,没有自我实现,所以是无码专区 主要是为了训练思维能力 my idea顾名思义,记录了我的整个思维过程,以及自己部分实现细节口胡,还有期望分数 solution才是dls正解,但是因为只 ...

  2. Android 生成二维码,条形码,二维码添加logo

    zxing生成二维码 implementation 'com.google.zxing:core:3.3.1' implementation(name: 'zxing-1.0.1', ext: 'aa ...

  3. 初识二维码 第二十讲 二维码解码程序的组件之一 摄像头拍照功能

    初识二维码 第二十讲    二维码解码程序的组件之一 摄像头拍照功能 解码程序的第一个环节是通过摄像头这个硬件,得到二维码的图片. 对摄像头的工作原理来说,简单的描述如下:1是从摄像头得到模拟信号, ...

  4. 点分治 + 树状数组 ---- E. Close Vertices(点分治 + 二维数点)

    题目链接 题目大意: 给出一棵树,问有多少条路径权值和不大于www,长度不大于lll 解题思路: 首先树上路径问题大概率就是点分治了 但是我们对于每个路径有两个性质就是(li,wi)(l_i,w_i) ...

  5. js 生成二维码_QRcode.js 生成二维码

    github官方文档指路:https://github.com/soldair/node-qrcode#options QRcode方法介绍: 这里只介绍后三种常用方法的使用: 1.toCanvas ...

  6. 洛谷 - P3899 [湖南集训]谈笑风生(dfs序+主席树/二维数点)

    题目链接:点击查看 题目大意:设 TTT 为一棵有根树,我们做如下的定义: 设 aaa 和 bbb 为 TTT 中的两个不同节点.如果 aaa 是 bbb 的祖先,那么称"aaa 比 bbb ...

  7. 洛谷 - P2163 [SHOI2007]园丁的烦恼(不带修二维数点-树状数组/主席树)

    题目链接:点击查看 题目大意:二维平面坐标系中给出 nnn 个坐标点,然后是 mmm 次询问,每次询问需要回答一个闭合矩阵中有多少个点 题目分析:想挂树套树来着,但是复杂度有点大.本题不带修且可以离线 ...

  8. P3899 [湖南集训]谈笑风生 主席树解决二维数点

    传送门 文章目录 题意: 思路: 题意: 思路: 由于a,ba,ba,b都比ccc厉害,那么a,ba,ba,b一定是某个是某个的祖先.那么就分为两种情况了: (1)(1)(1) bbb在aaa上面,约 ...

  9. LG P4899 [IOI2018] werewolf 狼人(kruskal重构树,二维数点)

    LG P4899 [IOI2018] werewolf 狼人 Solution 我们发现010101限制长这样子: ∃x(minids−>x≥L&maxidx−>e≤R)→1\ex ...

最新文章

  1. Asp.Net Web API 2第一课——入门
  2. mysql 一键脚本_mysql一键安装脚本
  3. python json库安装_win 安装python的cjson库
  4. 机器学习导论(张志华):正定核应用
  5. 用python定义一个员工类_python3 类的定义
  6. TensorFlow学习笔记之五(卷积神经网络)
  7. boost的chrono模块时间间隔的测试程序
  8. code vs 集成tfs_关于编译器和集成开发环境,一文给你讲明白!
  9. Flex Skin Design Extensions Flex Component Kit 下载.
  10. [转载]工作面试时最难的25个问题
  11. Concept3D推出交互式3D地图平台
  12. Ergo生态:首个算法稳定币SigmaUSD正式启动
  13. AOP Aspect Oriented Programming
  14. 做测试开发半年涨薪20W入职名企大厂,这位90后凭什么?
  15. Putty工具使用教程
  16. json 转 map,循环得到 key,value
  17. 计算机科学与技术代码0812,一级学科代码及名称0812计算机科学与技术(2007年)本.doc...
  18. BCR-ABL融合基因及检测
  19. oracle 数据库不用了,改用SQL,要学SQL了,第一个手工写的存储过程
  20. Docker(八)Container无法正常启动Restarting (1) Less than a second ago的原因及解决办法

热门文章

  1. 是学习Java还是Python?一张图告诉你!
  2. matlab中给图像加几个矩形框_没想到!PPT中的这个效果,用好了,简直就是渣图美化器...
  3. php文字左右滚动代码,JavaScript
  4. php获取某地的ip,php获取本土实际IP
  5. Java如何控制用户输入的长度,用Java Applet 进行Web编程时,如何限制输入域中可输入字符的长度!解决后马上给分!!!...
  6. java类同步_Java中方法,对象,类的同步
  7. mysql函数保留小数_MySql自定义函数-关于保留小数位的特殊需求
  8. 关于-32768补码的问题
  9. hdu2648 Shopping-map容器
  10. Android程序设计基础-设计布局之伪今日头条主界面