Angle Beats Gym

Angle Beats

$$ Time Limit: 4000 ms \quad Memory Limit: 1048576 kB $$

题意

给出 $n$ 个初始点以及 $q$ 次询问,每次询问给出一个询问点 $Q$,求包括 $Q$ 点的直角三角形有多少个。保证 $n+q$ 个点都不重复。

思路

  1. 对于每次询问,当 $Q$ 为直角点时,以 $Q$ 为原点,对 $n$ 个点做象限极角排序,然后用双指针 $L$、 $R$ 维护直角三角形的个数。 $L$ 指针用来枚举其中的一条直角边, $R$ 指针用来寻找在另一条直角边上的点有多少个,每次找 $QL$ 这条边逆时针方向的另一条边$QR$。所以当 $L$ 往逆时针转动时,$R$ 也会往逆时针转动,那么就可以用双指针直接维护出来了,特别注意一下多个点在同一条直线上的情况就可以了。
  2. 若 $Q$ 不是直角点时,可以离线处理,把 $n+q$ 个点全部存出来,然后枚举以 $n$ 个初始点为直角点时,对哪些的 $Q$ 点有贡献,维护方法同上。

最后的复杂度为 $O\left(qnC_1 + n(n+q)C_2\right)$,$C_1、C_2$ 取决于在枚举直角点为原点后,到原点在同一条直线上的点数量。 我试过把 $n+q$ 个节点全部提取出来,然后暴力枚举每个点为直角点的情况,但是这样复杂度会 $T$。

1#include<bits/stdc++.h> 2using namespace std; 3typedef long long ll; 4typedef unsigned long long ull; 5const int maxn = 1e4+10; 6 7struct Point { 8 ll x, y; 9 int id; 10} p[maxn], be[maxn]; 11int n, m; 12int ans[maxn]; 13 14int cmp1(Point a, Point b) { 15 ll d = a.x*b.y - b.x*a.y; 16 if(d == 0) { 17 return a.x<b.x; 18 } else { 19 return d>0; 20 } 21} 22int Qua(Point a) { 23 if(a.x>0 && a.y>=0) return 1; 24 if(a.x<=0 && a.y>0) return 2; 25 if(a.x<0 && a.y<=0) return 3; 26 if(a.x>=0 && a.y<0) return 4; 27} 28 29int cmp(Point a, Point b) { 30 if(Qua(a) == Qua(b)) return cmp1(a, b); 31 else return Qua(a)<Qua(b); 32} 33 34ll check(Point a, Point b) { 35 return a.x*b.x + a.y*b.y; 36} 37 38ll chaji(Point a, Point b) { 39 return a.x*b.y - b.x*a.y; 40} 41 42ll work(Point pp) { 43 for(int i=1; i<=n; i++) { 44 p[i] = be[i]; 45 p[i].x -= pp.x; 46 p[i].y -= pp.y; 47 } 48 p[0] = pp; 49 sort(p+1, p+1+n, cmp); 50 for(int j=1; j<=n; j++) { 51 p[j+n] = p[j]; 52 } 53 ll ans = 0; 54 int R = 2; 55 for(int L=1; L<=n; L++) { 56 while(R<=2*n) { 57 if(chaji(p[L], p[R]) < 0) break; 58 if(check(p[L], p[R]) <= 0) break; 59 R++; 60 } 61 int tR = R; 62 while(tR<=2*n) { 63 if(chaji(p[L], p[tR]) <= 0) break; 64 if(check(p[L], p[tR]) != 0) break; 65 ans++; 66 tR++; 67 } 68 } 69 return ans; 70} 71 72int main(){ 73 // freopen("in", "r", stdin); 74 while(~scanf("%d%d", &n, &m)) { 75 int all = 0; 76 for(int i=1; i<=n; i++) { 77 all++; 78 int x, y; 79 scanf("%d%d", &x, &y); 80 p[all].x = x, p[all].y = y, p[all].id = 0; 81 be[all] = p[all]; 82 } 83 for(int i=1; i<=m; i++) { 84 all++; 85 int x, y; 86 scanf("%d%d", &x, &y); 87 p[all].x = x, p[all].y = y, p[all].id = i; 88 be[all] = p[all]; 89 ans[i] = work(p[all]); 90 } 91 for(int i=1; i<=n; i++) { 92 for(int j=1; j<=all; j++) { 93 p[j] = be[j]; 94 } 95 p[0] = be[i]; 96 int flag = 0; 97 for(int j=1; j<=all; j++) { 98 if(p[j].x == p[0].x && p[j].y == p[0].y) flag = 1; 99 if(flag) p[j] = p[j+1]; 100 p[j].x -= p[0].x; 101 p[j].y -= p[0].y; 102 } 103 104 int nn = all-1; 105 sort(p+1, p+1+nn, cmp); 106 for(int j=1; j<=nn; j++) { 107 p[j+nn] = p[j]; 108 } 109 int R = 2; 110 for(int L=1; L<=nn; L++) { 111 int id = 0; 112 if(p[0].id) id = p[0].id; 113 if(p[L].id) id = p[L].id; 114 while(R<=2*nn) { 115 if(chaji(p[L], p[R]) < 0) break; 116 if(check(p[L], p[R]) <= 0) break; 117 R++; 118 } 119 int tR = R; 120 while(tR<=2*nn) { 121 if(chaji(p[L], p[tR]) <= 0) break; 122 if(check(p[L], p[tR]) != 0) break; 123 if(id == 0) { 124 if(p[tR].id) ans[p[tR].id]++; 125 } else { 126 if(p[tR].id == 0) ans[id]++; 127 } 128 tR++; 129 } 130 } 131 } 132 for(int i=1; i<=m; i++) { 133 printf("%d\n", ans[i]); 134 } 135 } 136 return 0; 137}
点赞
收藏

评论区

加载中...

相关推荐

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

sql 查询

高效SELECTq.ID\_ANSWER,q.ID\_QUESTION,q.CONTENT,q.UPVOTE\_TOTE,q.IS\_ADOPT,q.ID\_USER,q.OPPOSE\_TOTE,q.ANSWER\_TIME,q.ACT\_FLAG,q.SCORE,u.OFFICIAL\_EXPERT,qs.TITLE,qs.I

前端性能优化 - 雅虎军规

无论是在工作中,还是在面试中,web前端性能的优化都是很重要的,那么我们进行优化需要从哪些方面入手呢?可以遵循雅虎的前端优化35条军规,这样对于优化有一个比较清晰的方向.35条军规1.尽量减少HTTP请求个数——须权衡2.使用CDN(内容分发网络)3.为文件头指定Expires或CacheControl,使内容具有缓存性。4.避免空的

python-算法训练 区间k大数查询

问题描述给定一个序列,每次询问序列中第l个数到第r个数中第K大的数是哪个。输入格式第一行包含一个数n,表示序列长度。第二行包含n个正整数,表示给定的序列。第三个包含一个正整数m,表示询问个数。接下来m行,每行三个数l,r,K,表示询问序列从左往右第l个数到第r个数中,从大往小第K大的数是哪个。序列元素从1开始标号。输出格式总共输出m行,每行一个数

Codeforces 862B (二分图染色)

<题目链接(https://www.oschina.net/action/GoToLink?urlhttps%3A%2F%2Fvjudge.net%2Fproblem%2FCodeForces862B)\题目大意:给出一个有n个点的二分图和n1条边,问现在最多可以添加多少条边使得这个图中不存在自环,重边,并且此图还是一个二

HDU 3416 Marriage Match IV (Dijkstra+最大流)

题意:N个点M条边的有向图,给定起点S和终点T,求每条边都不重复的ST的最短路有多少条。分析:首先第一步需要找出所有可能最短路上的边。怎么高效地求出呢?可以这样:先对起点S,跑出最短路;对于每条边e(u,v,w),若d\u\wd\v\。那么e就是最短路上的一条边。在前向星存储的图中遍历即可。网上还有题解用的方法是分别从S和T跑两