[BZOJ]4418: [Shoi2013]扇形面积并 线段树

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);
}
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值