• Codeforces 350D(计算几何)


    要点

    • 用A、B、C一般式确定每条直线
    • 将合法的圆心中点存到每条直线所属的vector中
    • 枚举所有线段,二分后(O(1))得到其中存在多少答案,累加
    #include <cstdio>
    #include <cmath>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #include <iomanip>
    #include <vector>
    #include <unordered_map>
    using namespace std;
    
    typedef long long ll;
    const int maxn = 3e5 + 5, maxm = 1550;
    const ll inf = 1e18;
    
    struct Point {
    	ll x, y;
    	Point() {}
    	Point(ll a, ll b):x(a), y(b) {}
    };
    struct Circle {
    	Point p;
    	ll r;
    	Circle() {}
    	Circle(Point a, ll b):p(a), r(b) {}
    };
    
    int n, m, hashcnt;
    Point a[maxn], b[maxn];//segments
    Circle c[maxm];//circles
    unordered_map<ll, int> mp;//<{A, B, C}, id>
    vector<ll> v[maxn];//v[id]
    ll A, B, C;//a few times used
    ll ans;
    int ID[maxn];
    
    ll sqr(ll x) {
    	return x * x;
    }
    
    ll dis(int i, int j) {//distance ^ 2
    	return sqr(c[i].p.x - c[j].p.x) + sqr(c[i].p.y - c[j].p.y);
    }
    
    ll gcd(ll a, ll b) {//exist zero: return
    	if (!a || !b)	return a + b;
    	return gcd(b, a % b);
    }
    
    ll Cross(Point A, Point B) {
    	return A.x * B.y - A.y * B.x;
    }
    
    void Deal(ll &A, ll &B, ll &C) {//unique the line
    	ll q = gcd(gcd(abs(A), abs(B)), abs(C));
    	A /= q, B /= q, C /= q;
    	if (A == 0 && B < 0)	B = -B, C = -C;	
    	else if (A < 0)	A = -A, B = -B, C = -C;
    }
    
    ll hashi(ll A, ll B, ll C) {//map is TLE, so I hash it
    	return A * (ll)(1e12) + B * (ll)(1e6) + C;
    }
    
    void Hash(int i, ll A, ll B, ll C) {
    	ll d = hashi(A, B, C);
    	if (!mp.count(d)) {
    		mp[d] = ++hashcnt;
    	}
    	int id = mp[d];
    	ID[i] = id;
    }
    
    void calc(Point a, Point b) {// get A, B, C
    	A = b.y - a.y, B = a.x - b.x;
    	C = Cross(b, a);//Ax + By + C = 0	
    	Deal(A, B, C);
    }
    
    int main() {
    	scanf("%d %d", &n, &m);
    	for (int i = 1; i <= n; i++) {
    		scanf("%lld %lld %lld %lld", &a[i].x, &a[i].y, &b[i].x, &b[i].y);
    		a[i].x *= 2, a[i].y *= 2, b[i].x *= 2, b[i].y *= 2;//for line 99
    		if (a[i].x > b[i].x)	swap(a[i], b[i]);//for line 109 & 110
    		calc(a[i], b[i]);
    		Hash(i, A, B, C);
    	}
    	for (int i = 1; i <= m; i++) {
    		scanf("%lld %lld %lld", &c[i].p.x, &c[i].p.y, &c[i].r);
    		c[i].p.x *= 2, c[i].p.y *= 2, c[i].r *= 2;
    		for (int j = 1; j < i; j++)
    			if (c[i].r == c[j].r && dis(i, j) > 4LL * sqr(c[i].r)) {//if eyes
    				calc(c[i].p, c[j].p);
    				ll A1 = B * 2, B1 = -A * 2;
    				ll C1 = A * (c[i].p.y + c[j].p.y) - B * (c[i].p.x + c[j].p.x);
    				Deal(A1, B1, C1);
    				ll d = hashi(A1, B1, C1);
    				if (!mp.count(d))	continue;
    				ll x = (c[i].p.x + c[j].p.x) / 2;//line 99: should avoid double
    				v[mp[d]].emplace_back(x);
    			}
    	}
    	for (int i = 1; i <= hashcnt; i++) {
    		v[i].emplace_back(inf);
    		sort(v[i].begin(), v[i].end());
    	}
    	for (int i = 1; i <= n; i++) {
    		int id = ID[i];
    		int l = lower_bound(v[id].begin(), v[id].end(), a[i].x) - v[id].begin();//line 109
    		int r = upper_bound(v[id].begin(), v[id].end(), b[i].x) - v[id].begin();//line 110
    		ans += r - l;
    	}
    	return !printf("%lld
    ", ans);
    }
    
  • 相关阅读:
    udev文件系统的使用和基本工作原理分析
    ARM平台上蓝牙协议栈Bluez的移植使用和配置
    udev文件系统的使用和基本工作原理分析
    ARM平台上蓝牙协议栈Bluez的移植使用和配置
    Linux 下用户空间与内核空间数据交换的方式
    详解Linux2.6内核中基于platform机制的驱动模型
    IOS怎么判断网络连接
    ios 设备方向判断
    IOS加解密
    用代码向网站提交数据
  • 原文地址:https://www.cnblogs.com/AlphaWA/p/10997417.html
Copyright © 2020-2023  润新知