1. 程式人生 > >計蒜客 直線的交點(計算幾何 + 逆序對)

計蒜客 直線的交點(計算幾何 + 逆序對)

clas ret ons oid date pda 所有 efi define

題目鏈接 直線的交點

兩條直線的交點如果落在兩個平板之內的話

假設這兩條直線和兩條平板的交點橫坐標分別為 $x1, x2, X1, X2$

那麽有$(x2 - x1)(X2 - X1) < 0$

於是這就轉化成了一個經典問題

我們求出所有直線和平板的兩個交點的橫坐標,按其中一個平板的橫坐標排序,

然後對另一個平板的橫坐標求逆序對即可。

#include <bits/stdc++.h>

using namespace std;

#define rep(i, a, b)	for (int i(a); i <= (b); ++i)
#define dec(i, a, b)	for (int i(a); i >= (b); --i)

typedef long long LL;

const int N = 1e5 + 10;

double k, b1, b2;
double a[N], b[N];
int f[N], t[N], n;
LL  ans = 0;

struct node{
	double x, y;
	int id;
	friend bool operator < (const node &a, const node &b){
		return a.x < b.x;
	}
} c[N];


bool cmp(const node &a, const node &b){ return a.y < b.y; }
double calc(double k1, double b1, double k2, double b2){ return (b2 - b1) / (k1 - k2);}

void update(int x){ for (; x <= n; x += x & -x) ++t[x];}
int query(int x){ int ret(0); for (; x; x -= x & -x) ret += t[x]; return ret;}


int main(){

	scanf("%lf%lf%lf", &k, &b1, &b2);
	scanf("%d", &n);

	rep(i, 1, n) scanf("%lf%lf", a + i, b + i);
	rep(i, 1, n) c[i].x = calc(a[i], b[i], k, b1);
	rep(i, 1, n) c[i].y = calc(a[i], b[i], k, b2);

	sort(c + 1, c + n + 1);
	rep(i, 1, n) c[i].id = i;
	sort(c + 1, c + n + 1, cmp);
	rep(i, 1, n) f[c[i].id] = i;

	dec(i, n, 1) ans += (LL)query(f[i] - 1), update(f[i]);

	printf("%lld\n", ans);
	return 0;
}

計蒜客 直線的交點(計算幾何 + 逆序對)