【BZOJ4418】[Shoi2013]扇形面积并 扫描线+线段树

【BZOJ4418】[Shoi2013]扇形面积并

Description

给定N个同心的扇形,求有多少面积,被至少K个扇形所覆盖。

Input

第一行是三个整数n,m,k。n代表同心扇形的个数,m用来等分 [-π,π]的弧度。
从第二行开始的n行,每行三个整数r,a1,a2。描述了一个圆心在原点的扇形,半径为r,圆心角是从弧度πa1/m到πa2/m,a1可能大于a2,逆时针扫过的区域为该扇形面积。

Output

输出一个整数ans,至少被K个扇形所覆盖的总面积等于π/2m×ans
保证答案不超过2^63-1

Sample Input

【输入样例1】
3 8 2
1 -8 8
3 -7 3
5 -5 5
【输入样例2】
2 4 1
4 4 2
1 -4 4

Sample Output

【输出样例1】
76
【输出样例2】
98

HINT

对于100%的数据,1≤n≤10^5,   1≤m≤10^6,1≤k≤5000,1≤ri≤10^5,-m≤a1,a2≤m

题解:现将扇形掰开变成矩形,然后用扫描线处理,每个矩形都改成差分的形式。由于对于任意一条与x轴垂直的先,里面的点被覆盖的层数一定不会比外面少,所以我们可以在线段树上二分,时间复杂度$O(nlogr)$。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define lson x<<1
#define rson x<<1|1
using namespace std;

const int maxn=100010;
typedef long long ll;
int n,m,tot,R,K;
int s[maxn<<2];
ll ans;
struct node
{
	int x,y,k;
	node() {}
	node(int a,int b,int c) {x=a,y=b,k=c;}
}p[maxn<<2];
bool cmp(const node &a,const node &b)
{
	return a.x<b.x;
}
inline void pushup(int x)
{
	s[x]=s[lson]+s[rson];
}
void updata(int l,int r,int x,int a,int b)
{
	s[x]+=b;
	if(l==r)	return ;
	int mid=(l+r)>>1;
	if(a<=mid)	updata(l,mid,lson,a,b);
	else	updata(mid+1,r,rson,a,b);
}
int query(int l,int r,int x,int a)
{
	if(l==r)	return l;
	int mid=(l+r)>>1;
	if(s[rson]>=a)	return query(mid+1,r,rson,a);
	return query(l,mid,lson,a-s[rson]);
}
inline int rd()
{
	int ret=0,f=1;	char gc=getchar();
	while(gc<'0'||gc>'9')	{if(gc=='-')	f=-f;	gc=getchar();}
	while(gc>='0'&&gc<='9')	ret=ret*10+(gc^'0'),gc=getchar();
	return ret*f;
}
int main()
{
	n=rd(),m=rd(),K=rd();
	int i,a,b,c;
	for(i=1;i<=n;i++)
	{
		c=rd(),a=rd()+m,b=rd()+m,R=max(R,c);
		if(a<=b)	p[++tot]=node(a,c,1),p[++tot]=node(b,c,-1);
		else	p[++tot]=node(a,c,1),p[++tot]=node(2*m,c,-1),p[++tot]=node(0,c,1),p[++tot]=node(b,c,-1);
	}
	sort(p+1,p+tot+1,cmp);
	for(i=1;i<=tot;i++)
	{
		a=query(0,R,1,K),ans+=(ll)a*a*(p[i].x-p[i-1].x);
		updata(0,R,1,p[i].y,p[i].k);
	}
	printf("%lld",ans);
	return 0;
}
posted @ 2017-11-19 14:37  CQzhangyu  阅读(307)  评论(0编辑  收藏  举报