[BZOJ 3888] [Usaco2015 Jan] Stampede 【线段树】

题目链接:BZOJ – 3888

 

题目分析

首先,计算出每个线段在 x 坐标 0 处出现的时间开始点和结束点,就转成了时间轴上的线段。

然后就是看每条线段是否被 y 比它小的线段完全覆盖了。注意求出的时间点要离散化,然后应该使用时间轴上的区间来表示,两线段端点重合并不是有共同部分。

将所有线段按照 y 从小到大排序之后,使用线段树判断它覆盖的区间是否已经都被前面的线段覆盖了。

然后将它所覆盖的区间覆盖。

就这样的一道题我WA了7次,还有救吗..

 

代码

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

using namespace std;

const int MaxN = 100000 + 5;

map<int, int> M;

int n, Top, Ans, MN;
int NA[MaxN], T[MaxN * 4], D[MaxN * 4];

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

struct ES
{
	int s, t, Height;
} E[MaxN];

inline bool Cmp(ES e1, ES e2)
{
	return e1.Height < e2.Height;
}

inline void Paint(int x)
{
	T[x] = D[x] = 1;
}

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

int Get(int x, int s, int t, int l, int r)
{
	if (l <= s && r >= t) return T[x];
	PushDown(x);
	int m = (s + t) >> 1, ret = 1;
	if (l <= m) ret = gmin(ret, Get(x << 1, s, m, l, r));
	if (r >= m + 1) ret = gmin(ret, Get(x << 1 | 1, m + 1, t, l, r));
	return ret;
}

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

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

int main()
{
	scanf("%d", &n);
	int x, y, r;
	for (int i = 1; i <= n; ++i)
	{
		scanf("%d%d%d", &x, &y, &r);
		E[i].Height = y;
		E[i].s = (-x - 1) * r;
		E[i].t = E[i].s + r;
		NA[++Top] = E[i].s;
		NA[++Top] = E[i].t;
	}
	sort(NA + 1, NA + Top + 1);
	int p = 0;
	for (int i = 1; i <= Top; ++i)	
	{
		if (i != 1 && NA[i] == NA[i - 1]) continue;
		M[NA[i]] = ++p;
	}
	for (int i = 1; i <= n; ++i)
	{
		E[i].s = M[E[i].s];
		E[i].t = M[E[i].t] - 1;
	}
	sort(E + 1, E + n + 1, Cmp);
	MN = n * 2 + 5;
	for (int i = 1; i <= n; ++i)
	{
		if (Get(1, 1, MN, E[i].s, E[i].t) == 0) ++Ans;
		Cover(1, 1, MN, E[i].s, E[i].t);
	}
	printf("%d\n", Ans);
	return 0;
}

  

    原文作者:JoeFan
    原文地址: https://www.cnblogs.com/JoeFan/p/4434000.html
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞