JZOJ3441 小喵喵的新家
Description
小喵喵和小聪聪从小就是好朋友 ,他们经常在一起玩耍 。如今小喵已经厌倦了自己居住的环境,想请小聪聪为她建一个新家。
小喵喵天生多才多艺,对多种乐器颇有研究。对于生活中常见的图形,她对圆形很感兴趣,因此小聪聪决定为她建一个圆形的新家。
我们设新家在一个平面直角坐标系上,其中新家的圆心为平面直角坐标系的原点。
小聪聪有一把神奇的剪刀,他定义了一个值m,以等分 [−pi,pi]弧度 (详见样例)。他还有一支神奇的画笔,将进行 n次“铺地毯”操作。对于第i 次“铺地毯”操作,他将设定一个半径ri,起始位置si,终止位置ti ,然后从圆心角pi*si/m到圆心角pi*ti/m这部分区域逆时针铺上一个扇形地毯。
小喵喵想到了一个奇怪的问题,她想知道有多大面积被至少铺过k次地毯。 这个问题一下就难倒了聪明的小聪聪。 现在小聪聪求助于你,你能帮他解决这个问题吗?为了方便表达 ,设答案的值为T,你只需要输出 T×2m/ π 的值即可 。
Input
第一行是三个整数 n,m,k,含义 如题目描述中所述。
接下来n行, 每行描述一次铺地毯操作 。第i行有三个整数r,si,ti,含义 如 题目描述中所述。
Output
输出 一个整数 表示T×2m/ π 的值。
Sample Input
3 8 2
1 -8 8
3 -7 3
5 -5 5
Sample Output
76
Data Constraint
Hint
分析:
出题人用心良苦,不卡精度。
实际上算面积的时候很简单。
本来在题中扇形面积的计算公式是这样的:
S扇形=所占的份数2mπr2
由于“你只需要输出 T×2m/π的值即可 ”,所以就变成了:
S扇形=所占的份数r2
把整幅图看作一个半径为100000的大圆。
它被分成了2m份,我们一份一份求覆盖不小于k次的面积。
如图所标,我们红色的扇形被三条毛毯所穿过,题目说被不少于k条毛毯覆盖,那我们就从半径最大的那条毛毯往内数,数够k条后,你会发现当前那条第k长的半径所围起来的地方就是该部分被不少于k条毛毯所覆盖的地方。
当我们知道一部分中有哪些半径时,我们通过二分,就能求出答案。
那一个部分中有什么半径,我们怎么知道呢?
我们把圆拆成一条线段,端点就是圆圈上的各个等分点。把地毯的半径视为高,连接起始点和终点,如果有横跨线段中点的,把它看作两个部分。然后把起点和终点分别存出来,附带半径长,按照端点排序(边集数组会更快)。
样例如下图:
设g[r]表示现在半径为r的半径有多少条。
我们可以从-m扫过去,碰到起始点的时候就把其对应的g[r]+1,碰到结束点的时候就把其对应的g[r]-1。记得用线段树维护1-100000内g[r]的和。
之后利用线段树的基本性质二分:
现在有l,r,k1。
mid=(l+r)/2;
我们要在l,r中找一个最大的a,使得 ∑ri=ag[i] =k1。
如果 ∑ri=mid+1g[i] >=k1,则说明a一定在mid+1—r中,递归(mid+1,r,k1)。否则,a要么在l—mid中,要么不存在,递归(l,mid,k1- ∑ri=mid+1g[i] )。
之所以要减去 ∑ri=mid+1g[i] ,是因为我们要使 ∑ri=ag[i] =k1,而 ∑ri=mid+1g[i] 是包括在内的,所以递归下去也要算,就直接把它减去。
找到a以后,答案加上 a2 ,注意开long long(int 64)。
Code:
#include<cstdio>
#define fo(i,x,y) for(int i=x;i<=y;i++)
using namespace std;
int n,m,k,r,s,t,tot,tail,d[500000],x[500000],l[200001],w[200001];;
long long ans;
int v(int x){
if(x<0) return -x+100000; else return x;
}
struct cc{
int a,b,c;
}b[500001];
void change(int x,int y,int i,int a,int c){
if(x==y){
d[i]+=c;
return;
}
int m=(x+y)/2;
if(a<=m) change(x,m,i+i,a,c); else change(m+1,y,i+i+1,a,c);
d[i]=d[i+i]+d[i+i+1];
}
int find(int x,int y,int i,int k){
if(x==y) return d[i]>=k?x:0;
int m=(x+y)/2;
return d[i+i+1]>=k?find(m+1,y,i+i+1,k):find(x,m,i+i,k-d[i+i+1]);
}
void insert(int x,int y){
b[++tot].a=x; b[tot].b=y; b[tot].c=r;
}
int main(){
scanf("%d%d%d",&n,&m,&k);
fo(i,1,n){
scanf("%d%d%d",&r,&s,&t);
if(s==-m||s==m){
insert(-m,1); insert(t,-1);
} else {
if(t==-m) t=m;
if(t>=s){
insert(s,1); insert(t,-1);
} else {
insert(s,1); insert(m,-1);
insert(-m,1); insert(t,-1);
}
}
}
fo(i,1,tot){
int j=v(b[i].a);
if(!l[j]) l[j]=i; else x[w[j]]=i;
w[j]=i;
}
fo(i,-m,m-1){
for(int j=l[v(i)];j;j=x[j])
change(1,100000,1,b[j].c,b[j].b);
long long p=find(1,100000,1,k);
ans+=p*p;
}
printf("%lld",ans);
}