HDU6127 简单几何 暴力二分

LINK

题意:给出n个点,每个点有个权值,可以和任意另外一点构成线段,值为权值积。现问过原点的直线中交所有线段的权值和的最大值,注意直线必不经过点

思路:直线可以将点集分为两侧,此时的权值为两侧点的乘积。而且由于是过原点的直线,所以不用暴力枚举两个点了...直接极角排序,这里我原先的极角排序有点小问题,最后还是找的别人的,以(0,x)为最小极角的。

然后前缀和权值以便分组求积。

枚举点,与原点相连作直线,然后以枚举点的对称点,二分找到最大的在它顺时针侧的点,然后注意要注意枚举点是否包含的两种情况,这样分成两部分求积即可。

 

/** @Date    : 2017-08-16 13:18:05
  * @FileName: 1008.cpp
  * @Platform: Windows
  * @Author  : Lweleth (SoungEarlf@gmail.com)
  * @Link    : https://github.com/
  * @Version : $Id$
  */
#include <bits/stdc++.h>
#define LL long long
#define PII pair<int ,int>
#define MP(x, y) make_pair((x),(y))
#define fi first
#define se second
#define PB(x) push_back((x))
#define MMG(x) memset((x), -1,sizeof(x))
#define MMF(x) memset((x),0,sizeof(x))
#define MMI(x) memset((x), INF, sizeof(x))
using namespace std;

const int INF = 0x3f3f3f3f;
const int N = 5e4+20;
const double eps = 1e-6;

struct point
{
	LL x, y, v;
	point(){}
	point(LL _x, LL _y, LL _v):x(_x),y(_y),v(_v){}
	point(LL _x, LL _y):x(_x),y(_y){}
	point operator -(const point &b) const
	{
		return point(x - b.x, y - b.y);
	}
	LL operator *(const point &b) const 
	{
		return x * b.x + y * b.y;
	}
	LL operator ^(const point &b) const//少了个LL WA 3发
	{
		return x * b.y - y * b.x;
	}
};

int sign(double x)
{
	if(fabs(x) < eps)
		return 0;
	if(x < 0)
		return -1;
	else return 1;
}

LL xmult(point p1, point p2, point p0)  
{  
    return (p1 - p0) ^ (p2 - p0);  
}  

LL distc(point a, point b)
{
	return sqrt((double)((b - a) * (b - a)));
}

point p[N];
LL sum[N];

int cmp(point a, point b)//
{
	int t = xmult(a, b, point(0, 0));
	if(a.y * b.y <= 0)
	{
		if(a.y > 0 || b.y > 0)
			return a.y < b.y;
		if(a.y == 0 && b.y == 0)
			return a.x < b.x;
	}
	return xmult(a, b, point(0,0)) > 0;

}

int cmp1(const point &a, const point &b) //以(x,0)为基准点(最小极角)
{
    if (a.y == 0 && b.y == 0 && a.x*b.x <= 0)return a.x>b.x;
    if (a.y == 0 && a.x >= 0 && b.y != 0)return true;
    if (b.y == 0 && b.x >= 0 && a.y != 0)return false;
    if (b.y*a.y <= 0)return a.y>b.y;
    return xmult(a,b, point(0,0)) > 0 || (xmult(a,b,point(0,0)) == 0 && a.x < b.x);    
}

int bina(int x, int l, int r)
{
	int ans = -1;
	point ops = point(-p[x].x, -p[x].y);
	while(l <= r)
	{
		int mid = (l + r) >> 1;
		if(cmp1(ops, p[mid]) != 1)
		{
			l = mid + 1;
			ans = mid;
		}
		else r = mid - 1;
	}
	return ans;
}

int main()
{
	int T;
	cin >> T;
	while(T--)
	{
		MMF(sum);
		int n;
		scanf("%d", &n);
		for(int i = 1; i <= n; i++)
		{
			LL x, y, v;
			scanf("%lld%lld%lld", &x, &y, &v);
			p[i] = point(x, y, v);
		}
		sort(p + 1, p + n + 1, cmp1);
		/*for(int i = 1; i <= n; i++)
			printf("%lf %lf\n", p[i].x, p[i].y);*/
		LL ans = 0;
		for(int i = 1; i <= n; i++)
			sum[i] = sum[i - 1] + p[i].v;

		for(int i = 1; i <= n; i++)
		{
			if(p[i].y >= 0)
			{
				int r = bina(i, i + 1, n);
				if(r == -1)
					r = i;
				LL res1 = (sum[n] - (sum[r] - sum[i - 1])) * (sum[r] - sum[i - 1]);
				LL res2 = (sum[n] - (sum[r] - sum[i])) * (sum[r] - sum[i]);
				ans = max(max(res1, res2), ans);
				//cout << ans <<"r "<< r << endl;
			}
			else
			{
				int l = bina(i, 1, i);
				if(l == -1)
					l = 0;
				LL res1 = (sum[n] - (sum[i] - sum[l])) * (sum[i] - sum[l]);
				LL res2 = (sum[n] - (sum[i - 1] - sum[l])) * (sum[i - 1] - sum[l]);
				ans = max(max(res1, res2), ans);
				//cout <<i <<"~" << res1 << " l: " << l<<endl;
			}
		}
		printf("%lld\n", ans);
	}
    return 0;
}
/*
999
9


0 1 7
1 0 8
0 -1 9
-1 0 10
1 1 2
0 0 1
1 -1 4
-1 1 5
-1 -1 3
1.000000 0.000000
0.000000 0.000000
1.000000 1.000000
0.000000 1.000000
-1.000000 1.000000
-1.000000 0.000000
-1.000000 -1.000000
0.000000 -1.000000
1.000000 -1.000000
*/
posted @ 2017-08-18 19:47  Lweleth  阅读(199)  评论(0编辑  收藏  举报