思路:對所有的點進行極角座標排序,然後從最小的點開始,對每個點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;
}