Description
给定N个同心的扇形,求有多少面积,被至少K个扇形所覆盖。
题解:
对半径开权值线段树,将每个扇形拆成两个操作:加入一条半径或删除一条半径,每进行一次操作,用线段树找当前的第k大(也就是找当前用来算答案的的半径是多少),算答案,即可。
代码:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define LL long long
const int maxn=100010;
int n,m,k;
struct node{int x,f,r;}a[maxn*4];
bool cmp(node x,node y){return x.x<y.x;}
int len=0;
void work(int r,int a1,int a2)
{
a[++len].x=a1;a[len].r=r;a[len].f=1;
a[++len].x=a2;a[len].r=r;a[len].f=-1;
}
struct Tree{int l,r,c,lc,rc;}tr[maxn*2];
int trlen=0;
void build(int l,int r)
{
int t=++trlen;
tr[t].l=l;tr[t].r=r;tr[t].c=0;
if(l<r)
{
int mid=l+r>>1;
tr[t].lc=trlen+1;build(l,mid);
tr[t].rc=trlen+1;build(mid+1,r);
}
}
void add(int now,int p,int x)
{
if(tr[now].l==tr[now].r){tr[now].c+=x;return;}
int lc=tr[now].lc,rc=tr[now].rc,mid=tr[now].l+tr[now].r>>1;
if(p<=mid)add(lc,p,x);
else add(rc,p,x);
tr[now].c=tr[lc].c+tr[rc].c;
}
int query(int now,int k)
{
if(!k)return 0;
if(tr[now].c<k)return 0;
if(tr[now].l==tr[now].r)return tr[now].r;
int lc=tr[now].lc,rc=tr[now].rc,mid=tr[now].l+tr[now].r>>1;
if(k<=tr[lc].c)return query(lc,k);
else return query(rc,k-tr[lc].c);
}
int main()
{
int maxr=0;
scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=n;i++)
{
int r,a1,a2;
scanf("%d%d%d",&r,&a1,&a2);a1+=m;a2+=m;
if(a1<a2)work(r,a1,a2);
else work(r,0,a2),work(r,a1,m<<1);
maxr=max(maxr,r);
}
LL ans=0;
build(1,maxr);
sort(a+1,a+1+len,cmp);
for(int i=1;i<=len;i++)
{
if(i>1)
{
int t=query(1,tr[1].c-k+1);
if(t&&i>1)ans+=(LL)(t)*(LL)(t)*(LL)(a[i].x-a[i-1].x);
}
add(1,a[i].r,a[i].f);
}
printf("%lld",ans);
}