【 NOIP模拟考 】【 TEST 14 】【 T3 天神下凡 】

题目描述

DHC瘦是瘦,但有肌肉。他骨骼精奇,应堂发黑,理所当然的炼成了绝世神功“天神下凡”,DHC决定去找经常D他的KMZ报仇。KMZ拥有一片领地,几眼望不到头,所以我们认为是无限大。 DHC不敢正面和KMZ发生冲突,只敢在KMZ的领地上释放他的神功“天神下凡”,当他释放一次技能,会形成一个以目标点为圆心,半径 r 的圆形能量圈,能量圈的周围一圈有极强的能量,因此无法通过,所以圈内和圈外就被分割成了两个区域。而且能量圈也不能相交,否则会发生爆炸把DHC炸死,他当然不会犯这样的错,而内切或外切则没事。又因为DHC的神功初成,很不熟练,所以他只能以X轴上的点作为目标点。当他释放多次技能以后,地面上形成了若干个美丽的能量圈,他完全陶醉了,报仇神马的都不重要了,现在他只想知道地面被分割成了多少个区域。

输入输出格式

输入格式:

第一行一个正整数 n ,表示DHC释放了 n 次技能。

接下来n行,每行两个整数 x,r 。表示在坐标 (x , 0) 放了一次技能,半径为 r 。

输出格式:

 输出一个数,表示地面被分割成了几块。

( PS : 团队内图片 )

标准版的题解不仅要 用线段树维护,还需要离散化操作,不算很麻烦,(稍后附上解法 )  -_-

于是:::提供其他简单解法

因为题中圆不 相交,因此 一个圆 只可以 由 各个 小圆 组成,于是

我们只要 统计 每个圆 包含的 第一层 小圆 的 直径之和即可,最后比较一下 直径之和 是否等于 大圆直径 即可!!

手动画一下:

对于蓝色圆,只要统计深蓝色圆。

栈模拟  就能搞定!!

排序 : 

按 左端点 从小到大 ,左端点相同,那么 半径大的排在前面。

另外还有  并查集二分做法  ,过后提供!

#include <cstdio>
#include <algorithm>
#define LL long long

using namespace std;

inline int wread(){
	char c(getchar ());int wans(0),flag(1);
	while (c<'0' || c>'9'){if (c=='-') flag=-1;c=getchar ();}
	while (c>='0' && c<='9'){wans=wans*10+c-'0'; c=getchar ();}
	return wans*=flag;
}

int n;

struct node{int d,l,r;}a[300001];

bool e666 (node x,node y){
	if (x.l == y.l) {
		return x.d>y.d;
	}
	else return x.l<y.l;
}

int S[300001];

LL siz[300001];

LL ans;

int main (){
	
	n=wread();
	for (int i(1);i<=n;++i){
		int O(wread()),d(wread());
		a[i]=(node){d,O-d,O+d};
	}
	
	int top(0);
	
	sort(a+1,a+n+1,e666);
	
	S[++top] = 1 ;
	
	for (int i(2);i<=n;++i){
		node x(a[i]);
		while (x.l>=a[ S[top] ].r && top!=0)	top--;//
		if (top!=0)	siz[ S[top] ]+=x.d*2;
		S[++top]=i;
	}
	
	ans = (LL)n+1;
	
	for (int i(1);i<=n;++i)
		if ( siz[i] == a[i].d*2 )
			ans++;
	
	printf("%lld\n",ans);
	
	return 0;
}

猜你喜欢

转载自blog.csdn.net/violinlove/article/details/81607631