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