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


题解Here!

 

很容易想到把每个扇形转换成矩形,然后就变成了矩形覆盖。
于是扇形的半径就是举行的宽。
我们发现$a_1<a_2$就直接搞,那$a_1>a_2$呢?
我们可以将$[a_1,a_2],a_1>a_2$拆成$[a_1,m]+[-m,a_2]$,这个问题就解决了。
将每个矩形拆成两个操作:加入宽或删除宽。
这玩意很显然用权值线段树就好。
不会?静态区间第$k$大写过没?主席树写过没?
然后用扫描线把所有询问差分一下。
每进行一次操作,用线段树找当前的第$k$大(也就是找当前用来算答案的的半径是多少)。
然后就是一波乱搞算出答案了。
附上奇丑无比的代码:
#include<iostream>
#include<algorithm>
#include<cstdio>
#define LSON rt<<1
#define RSON rt<<1|1
#define DATA(x) a[x].data
#define LSIDE(x) a[x].l
#define RSIDE(x) a[x].r
#define MAXN 100010
using namespace std;
int n,m,q,d=0;
struct Segment_Tree{
	int data,l,r;
}a[MAXN<<2];
struct Fan{
	int r,x,c;
}b[MAXN<<2];
inline int read(){
	int date=0,w=1;char c=0;
	while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
	while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
	return date*w;
}
inline bool cmp(const Fan &p,const Fan &q){
	return p.x<q.x;
}
inline void add(int r,int x,int y){
	d++;
	b[d].r=r;b[d].x=x;b[d].c=1;
	d++;
	b[d].r=r;b[d].x=y;b[d].c=-1;
}
inline void pushup(int rt){
	DATA(rt)=DATA(LSON)+DATA(RSON);
}
inline void buildtree(int l,int r,int rt){
	LSIDE(rt)=l;RSIDE(rt)=r;
	if(l==r){
		DATA(rt)=0;
		return;
	}
	int mid=l+r>>1;
	buildtree(l,mid,LSON);
	buildtree(mid+1,r,RSON);
	pushup(rt);
}
void update(int l,int r,int c,int rt){
	if(l<=LSIDE(rt)&&RSIDE(rt)<=r){
		DATA(rt)+=c;
		return;
	}
	int mid=LSIDE(rt)+RSIDE(rt)>>1;
	if(l<=mid)update(l,r,c,LSON);
	if(mid<r)update(l,r,c,RSON);
	pushup(rt);
}
int query(int k,int rt){
	if(k<=0)return 0;
	if(DATA(rt)<k)return 0;
	if(LSIDE(rt)==RSIDE(rt))return LSIDE(rt);
	if(k<=DATA(LSON))return query(k,LSON);
	else return query(k-DATA(LSON),RSON);
}
void work(){
	long long ans=0;
	for(int i=1;i<=d;i++){
		if(i>1){
			int k=query(DATA(1)-q+1,1);
			if(k)ans+=1LL*k*k*(b[i].x-b[i-1].x);
		}
		update(b[i].r,b[i].r,b[i].c,1);
	}
	printf("%lld\n",ans);
}
void init(){
	int r,x,y,maxn=0;
	n=read();m=read();q=read();
	for(int i=1;i<=n;i++){
		r=read();x=read();y=read();
		x+=m;y+=m;
		maxn=max(maxn,r);
		if(x<=y)add(r,x,y);
		else{
			add(r,0,y);
			add(r,x,(m<<1));
		}
	}
	sort(b+1,b+d+1,cmp);
	buildtree(1,maxn,1);
}
int main(){
	init();
	work();
    return 0;
}

 

posted @ 2018-08-23 17:31  符拉迪沃斯托克  阅读(315)  评论(0编辑  收藏  举报
Live2D