[BZOJ 1218] [HNOI2003] 激光炸弹 【n logn 做法 - 扫描线 + 线段树】

题目链接:BZOJ - 1218

 

题目分析

可以覆盖一个边长为 R 的正方形,但是不能包括边界,所以等价于一个边长为 R - 1 的正方形。

坐标范围 <= 5000 ,直接 n^2 的二维前缀和,枚举每一个边长为 R - 1 的正方形就 AC 了 = =

但是,尽管 O(n^2) 的算法能水过,lct1999 神犇仍然坚持要写 O(n logn) 算法虐掉这道题,于是我 Orz 他也学着写了一下。

在神犇的讲解下,我写了这个算法:

首先将 n 个点按照 x 坐标排序,用一条竖直的扫描线,从左到右扫描每个点。

以这条扫描线为正方形的左边界,将在右边界之内的点都加入线段树,这个线段树是按照 y 坐标建立的。

我们应该求出的是 y 坐标的一个和最大的长度为 R 的区间,加入一个点或删除一个点会影响它所在的 R 个区间,这些区间是连续的一段,所以加点和删点就是区间修改。

又一次写区间修改不打标记,又一次被自己蠢哭了!

 

代码

#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <cstdio>
#include <algorithm>

using namespace std;

inline int gmax(int a, int b) {return a > b ? a : b;}
inline int gmin(int a, int b) {return a < b ? a : b;}

const int MaxN = 10000 + 5;

int n, R, Ans, Head, Tail;
int T[5000 * 4 + 15], D[5000 * 4 + 15];

struct Point
{
	int x, y, w;
	bool operator < (const Point &b) const
	{
		return x < b.x;
	}
} P[MaxN];

inline void Update(int x)
{
	T[x] = gmax(T[x << 1], T[x << 1 | 1]);
}

inline void Paint(int x, int Num) 
{
	D[x] += Num;
	T[x] += Num;
}

inline void PushDown(int x)
{
	if (D[x] == 0) return;
	Paint(x << 1, D[x]);
	Paint(x << 1 | 1, D[x]);
	D[x] = 0;
}

inline void Add(int x, int s, int t, int l, int r, int Num)
{
	if (l <= s && r >= t) 
	{
		Paint(x, Num);
		return;
	}
	PushDown(x);
	int m = (s + t) >> 1;
	if (l <= m) Add(x << 1, s, m, l, r, Num);
	if (r >= m + 1) Add(x << 1 | 1, m + 1, t, l, r, Num);
	Update(x);
}

int main()
{
	scanf("%d%d", &n, &R);
	for (int i = 1; i <= n; ++i)
		scanf("%d%d%d", &P[i].x, &P[i].y, &P[i].w);
	sort(P + 1, P + n + 1);
	Head = 1; Tail = 0;
	Ans = 0;
	for (int i = 1; i <= n; ++i)
	{
		while (Head <= i && P[Head].x < P[i].x) 
		{
			Add(1, 0, 5000, P[Head].y, gmin(5000, P[Head].y + R - 1), -P[Head].w);	
			++Head;
		}
		while (Tail < n && P[Tail + 1].x <= P[i].x + R - 1) 
		{
			++Tail;
			Add(1, 0, 5000, P[Tail].y, gmin(5000, P[Tail].y + R - 1), P[Tail].w);
		}
		Ans = gmax(Ans, T[1]);
	}
	printf("%d\n", Ans);
	return 0;
}

  

posted @ 2015-03-24 23:12  JoeFan  阅读(603)  评论(0编辑  收藏  举报