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
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
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;
}