现在的位置: 首页 > 综合 > 正文

vijos P1883月光的魔法

2018年04月24日 ⁄ 综合 ⁄ 共 2919字 ⁄ 字号 评论关闭

背景

影几欺哄了众生了,天以外——月儿何曾圆缺。

描述

有些东西就如同月光的魔法一般.

Luke是爱着vijos的.他想为自己心爱的东西画些什么——————就画N个圆吧.把它们的圆心都固定在x轴上.圆与圆.为了爱,两两不能相交.为了爱,它们可以互相贴在一起.内切或外切,都是允许的.

vijos的美丽,在于人心.vijos的孩子们,一定能告诉大家:Luke画的圆究竟把平面分割成了多少块?

月光恬美地洒在大地上.Luke知道,如果什么都不画,平面就只有一块.多美呢!Luke知道,只画一个圆,平面就分成了两块.也很美呢!但Luke还是要多画一些的,因为他真的深爱着vijos呢.

格式

输入格式

输入数据第一行:输出一个整数N,1<=N<=300,000.表示圆的个数.
之后N行,每一行有2个整数,x[i]和r[i]表示圆心固定在x[i]的位置,半径为r[i].
-1,000,000,000<=x[i]<=1,000,000,000
1<=r[i]<=1,000,000,000
所有圆都是唯一的,不会出现重叠.

输出格式

输出只有一行,要求输出平面被分割成了多少块.

样例1

样例输入1[复制]

2
1 3
5 1

样例输出1[复制]

3

样例2

样例输入2[复制]

3
2 2
1 1
3 1

样例输出2[复制]

5

样例3

样例输入3[复制]

4
7 5
-9 11
11 9
0 20

样例输出3[复制]

6

限制

对于40%的数据:
N<=5000.
对于100%的数据:
1<=N<=300,000;-1,000,000,000<=x[i]<=1,000,000,000;1<=r[i]<=1,000,000,000

题解

线段树的引用,我将圆按半径从大到小排列,用每个圆的编号在线段树上覆盖“该圆所覆盖的x轴”。线段树维护每一段中编号的最小值。之后从半径从小到大,若该圆所覆盖的x轴上编号最小=这个圆的编号,ans+1,否则ans+2.具体是为什么……好像画个图想想就好。

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<cmath>
#include<algorithm>
#define MAXN 300002
#define ll long long
using namespace std;
int n,b[MAXN<<1],cnt,hs[MAXN<<1],zz;
struct yuan{int o,r,L,R;} a[MAXN];
struct tree{int l,r,v,tag;} tr[MAXN*8];
ll ans;
int read()
{
	int x=0,f=1;
	char ch=getchar();
	while(ch<'0'||ch>'9') {if(ch=='-') f=-1; ch=getchar();}
	while(ch>='0'&&ch<='9') {x=x*10+(ch-'0'); ch=getchar();}
	return f*x;
}
bool kp(const yuan &i,const yuan &j) {return i.r>j.r;}
void init()
{
	n=read(); //printf("%d\n",n);
	int i,x,r;
	for(i=1;i<=n;i++)
	   {a[i].o=read(); a[i].r=read();
	    //printf("%d %d\n",a[i].o,a[i].r);
	    a[i].L=a[i].o-a[i].r; a[i].R=a[i].o+a[i].r;
	    //printf("%d %d\n",a[i].L,a[i].R);
	    b[++cnt]=a[i].L; b[++cnt]=a[i].R;
	   }
	sort(b+1,b+cnt+1);
	hs[1]=b[1]; zz=1;
	for(i=2;i<=cnt;i++)
	   {if(b[i]!=b[i-1]) hs[++zz]=b[i];}
	/*for(i=1;i<=zz;i++) printf("%d ",hs[i]);
	printf("\n");
	system("pause");*/
	sort(a+1,a+n+1,kp);
}
//------------------------------------------------------------------------------
void build(int w,int s,int e)
{
	tr[w].l=s; tr[w].r=e;
	if(s==e)
	   {tr[w].v=1<<30; tr[w].tag=-1; return ;}
	int mid=(s+e)>>1;
	build(w<<1,s,mid); build((w<<1)+1,mid+1,e);
}
int getw(int x)
{
	int s=1,e=zz,mid,w;
	while(s<=e)
	   {mid=(s+e)>>1;
	    if(hs[mid]>x) e=mid-1;
	    else {w=mid; s=mid+1;}
	   }
	return w;
}
void down(int w)
{
	if(tr[w].tag==-1) return;
	int l=w<<1,r=l+1,t=tr[w].tag;
	tr[w].tag=-1;
	tr[l].v=t; tr[l].tag=t; 
	tr[r].v=t; tr[r].tag=t; 
}
void insert(int w,int s,int e,int v)
{
	down(w);
	int l=tr[w].l,r=tr[w].r;
	if(s==l&&r==e)
	   {tr[w].v=v; tr[w].tag=v;
	    return ;
	   }
	int mid=(l+r)>>1;
	if(e<=mid) insert(w<<1,s,e,v);
	else if(s>mid) insert((w<<1)+1,s,e,v);
	else {insert(w<<1,s,mid,v); insert((w<<1)+1,mid+1,e,v);}
	tr[w].v=min(tr[(w<<1)+1].v,tr[w<<1].v);
}
int find(int w,int s,int e)
{
	down(w);
	int l=tr[w].l,r=tr[w].r;
	if(s==l&&r==e) return tr[w].v;
	int mid=(l+r)>>1;
	if(e<=mid) return find(w<<1,s,e);
	else if(s>mid) return find((w<<1)+1,s,e);
	else return min(find(w<<1,s,mid),find((w<<1)+1,mid+1,e));
}
void work()
{
	int i,s,e;
	for(i=1;i<=n;i++)
	   {s=getw(a[i].L); e=getw(a[i].R-1);
		insert(1,s,e,i);
	   }
	for(i=n;i>=1;i--)
	   {s=getw(a[i].L); e=getw(a[i].R-1);
	    int t=find(1,s,e); 
	    //printf("%d\n",t);
	    //system("pause");
	    if(t<=i) ans++;
	    else ans+=2;
	   }
	printf("%d\n",ans+1);
}
int main()
{
	init(); build(1,1,zz);
	work();
	return 0;
}

抱歉!评论已关闭.