思路:对所有的点进行极角坐标排序,然后从最小的点开始,对每个点i,二分查找它的极角逆时针旋转180度的角,在所有点之间的位置。如果这个角坐标的点是L右边的是R,只要求当前点到L点的权值总和,再算R顺时针转到i的权重总和.(这里用线段树维护下)。然后两个权重相乘就是当前直线的权值,然后总体取最大。
主要是要想到,对于n个点,做一条过原点的直线,将点集分为两块,这条直线的值就是,直线两边点权重总和乘得到的。然后去枚举这样的直线就行了。
#include <algorithm>
#include <bitset>
#include <cassert>
#include <climits>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <deque>
#include <iomanip>
#include <iostream>
#include <map>
#include <numeric>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <math.h>
using namespace std;
const int Max_N = 5*1e4+100;
#define M_PI1 3.141592653589793238462643383279502
int _sum, v;
int sumv[4*Max_N];
int l ,r , P;
void updata(int o, int L, int R)
{
int lc = o * 2, rc = o * 2 + 1;
int M = L + (R-L) / 2;
if (R == L) {
sumv[o] = v;
}
else {
if (P <= M) updata(o*2, L, M);
else updata(o*2+1, M+1, R);
sumv[o] = sumv[lc] + sumv[rc];
}
}
long long int query(int o, int L, int R)
{
if (l > R || r < L) return 0;
if (l <= L && r >= R) {
return sumv[o];
}
else {
int M = L + (R - L) / 2;
return query(o*2, L, M) + query(o*2 + 1, M + 1, R);
}
}
struct point{
int x, y, w;
double t;
};
int T;
int n;
const double eps = 1e-6;
bool cmp(const point &p1, const point &p2)
{
return p1.t < p2.t - eps;
}
point p[Max_N];
int main()
{
cin >> T;
while (T--) {
scanf("%d", &n);
memset(sumv, 0, sizeof(sumv));
for (int i = 1; i <= n; i++)
scanf("%d%d%d", &p[i].x, &p[i].y, &p[i].w);
for (int i = 1; i <= n; i++)
p[i].t = atan2(double(p[i].y), double(p[i].x));
sort(p+1, p+1+n, cmp);
for (int i = 1; i <= n; i++) {
P = i;
v = p[i].w;
updata(1, 1, n);
}
long long int ans1 = 0;
long long int ans2 = 0;
long long int ans = 0;
for (int i = 1; i <= n; i++) {
double t2 = p[i].t + M_PI1;
if (t2 > M_PI1 + eps) t2 = -(M_PI1-(t2-M_PI1));//取旋转180的角。
int l1 = 1; int r1 = n;
if (t2 + eps < p[1].t || t2 > p[n].t + eps) {
//cout << "ss" << endl;
l = 1; r = i;
ans1 = query(1, 1, n);
l = i+1; r = n;
if (l > n) ans2 = 0;
else ans2 = query(1, 1, n);
ans = max(ans, ans1 * ans2);
l = 1; r = i-1;
if (r <= 0) ans1 = 0;
else ans1 = query(1, 1, n);
l = i; r = n;
ans2 = query(1, 1, n);
ans = max(ans, ans1 * ans2);
// cout << ans << endl;
continue;
}
while(true) {
int mid = (l1 + r1) / 2;
if (p[mid].t > t2 + eps) r1 = mid;
else l1 = mid;
if (l1 + 1 == r1) break;
}
if (r1 > i) {
l = i; r = l1;
ans1 = query(1, 1, n);
l = r1; r = n;
ans2 = query(1, 1, n);
l = 1; r = i-1;
if (l >= 1)
ans2 += query(1, 1, n);
ans = max(ans, ans1 * ans2);
l = i+1; r = l1;
if (l < r)
ans1 = query(1, 1, n);
else ans1 = 0;
l = r1; r = n;
ans2 = query(1, 1, n);
l = 1; r = i;
ans2 += query(1, 1, n);
ans = max(ans, ans1 * ans2);
}
else {
l = r1; r = i;
ans1 = query(1, 1, n);
l = i+1; r = n;
if (l <= r)
ans2 = query(1, 1, n);
else ans2 = 0;
l = 1; r = l1;
ans2 += query(1, 1, n);
ans = max(ans, ans1 * ans2);
l = r1; r = i-1;
if (l <= r)
ans1 = query(1, 1, n);
else ans1 = 0;
l = i; r = n;
ans2 = query(1, 1, n);
l = 1; r = l1;
ans2 += query(1, 1, n);
ans = max(ans, ans1 * ans2);
}
}
printf("%lld\n", ans);
}
return 0;
}