H - Hard challenge HDU - 6127

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


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章