Lilliput Steps

小さな一歩から着実に. 数学やプログラミングのことを書きます.

JOI春合宿 2009-day4 Starry Sky

問題文 : 星空

解法 :
N個ある各星のLについて, そのLで囲める星の最大値を求める.

ここで, 走査をする際に, x軸のみを走査し, y軸はセグメント木で, "ある点に於いて観測できる星の最大値"を管理すると, x軸の走査がO(N), その過程でのセグメント木の走査がO(logN)で実現でき, O(N^2logN)時間でこの問題を解くことが出来る.

ただし, O(N^2logN)解法でも, 頑張って枝を狩らないと3secには間に合わないと考えられる. (僕の場合, 大きなケースでは4sec前後かかってしまいます...)

コード :

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <map>

#define MAX_N (4000)

using namespace std;

struct Star {
	int x, y, l;
	int my;
};

int segMax[1 << 13], segAdd[1 << 13];

void add(int a, int b, int x, int k = 0, int l = 0, int r = 1 << 12)
{
	if (b <= l || r <= a) return;
	
	if (a <= l && r <= b){
		segAdd[k] += x;
		while (k){
			k = (k - 1) / 2;
			segMax[k] = max(segMax[k * 2 + 1] + segAdd[k * 2 + 1], segMax[k * 2 + 2] + segAdd[k * 2 + 2]);
		}
		return;
	}
	add(a, b, x, k * 2 + 1, l, (l + r) / 2);
	add(a, b, x, k * 2 + 2, (l + r) / 2, r);
}

bool cmpx(const Star &a, const Star &b)
{
	return (a.x < b.x);
}

bool cmpl(const Star &a, const Star &b)
{
	return (a.l < b.l);
}

int main()
{
	int n;
	int ys[MAX_N], unq[MAX_N], x[MAX_N];
	Star dat[MAX_N], datl[MAX_N];
	map<int, int> conv;
	
	scanf("%d", &n);
	
	for (int i = 0; i < n; i++){
		scanf("%d %d %d", &dat[i].x, &dat[i].y, &dat[i].l);
		ys[i] = dat[i].my = dat[i].y;
		x[i] = dat[i].x;
	}
	
	sort(ys, ys + n);
	sort(x, x + n);
	
	int idx = 0;
	conv[ys[0]] = idx;
	unq[idx++] = ys[0];
	for (int i = 1; i < n; i++){
		if (ys[i] != ys[i - 1]){
			conv[ys[i]] = idx;
			unq[idx++] = ys[i];
		}
	}
	
	for (int i = 0; i < n; i++){
		dat[i].y = conv[dat[i].y];
		datl[i] = dat[i];
	}
	
	sort(dat, dat + n, cmpx);
	sort(datl, datl + n, cmpl);
	reverse(datl, datl + n);
	
	int res = 0;
	for (int i = 0; i < n; i++){
		int L = datl[i].l;
		int head = lower_bound(x, x + n, datl[i].x - L) - x;
		int tail = head;
		memset(segMax, 0, sizeof(segMax));
		memset(segAdd, 0, sizeof(segAdd));
		while (head != n){
			while (dat[head].x - dat[tail].x > L){
				if (dat[tail].l >= L) add(dat[tail].y, upper_bound(unq, unq + idx, dat[tail].my + L) - unq, -1);
				tail++;
			}
			if (dat[tail].x > datl[i].x) break;
			
			if (dat[head].l >= L){
				add(dat[head].y, upper_bound(unq, unq + idx, dat[head].my + L) - unq, 1);
			}
			res = max(res, segMax[0] + segAdd[0]);
			head++;
		}
	}
	
	printf("%d\n", res);
	
	return (0);
}