UOJ Logo zhouzixuan的博客

博客

bzoj 4418: [Shoi2013]扇形面积并

2016-03-08 14:26:12 By zhouzixuan
【题目描述】:
    给定N个同心的扇形,求有多少面积,被至少K个扇形所覆盖。
【题目解法】:
    转化以下模型变成:
    给你n个矩形,矩形的下端贴着x轴,询问有多少的面积至少被k个矩形覆盖
    对矩形的竖边扫描线,然后维护一个线段树,每次询问第k大的数字
    注意这里矩形的面积定义为a*h^2,a为底边长,h为高
    复杂度O(N log N)
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int N=100005;
const int M=500005;
struct node {int t;} tree[N*4];
struct Node
{
    int pos,h,flag;
    inline bool operator < (const Node &a) const
    {
        if (pos==a.pos) return flag<a.flag;
        return pos<a.pos;
    }
} a[M];
int n,m,limit,tot; long long ans;
inline long long getint()
{
    long long x=0; char c=getchar(); bool flag=false;
    while ((c!='-')&&((c<'0')||(c>'9'))) c=getchar();
    if (c=='-') flag=true,c=getchar();
    while ((c>='0')&&(c<='9')) x=x*10+(long long)(c-'0'),c=getchar();
    if (flag) return -x; else return x;
}
void init()
{
    n=getint(); m=getint(); limit=getint(); tot=0; int nowm=0;
    for (int i=1; i<=n; i++)
    {
        int h=getint(),l=getint(),r=getint(); nowm=max(nowm,h);
        if (l<=r)
        {
            ++tot; a[tot].pos=l; a[tot].flag=1; a[tot].h=h;
            ++tot; a[tot].pos=r; a[tot].flag=-1; a[tot].h=h;
        }
        if (l>r)
        {
            ++tot; a[tot].pos=-m; a[tot].flag=1; a[tot].h=h;
            ++tot; a[tot].pos=r; a[tot].flag=-1; a[tot].h=h;
            ++tot; a[tot].pos=l; a[tot].flag=1; a[tot].h=h;
            ++tot; a[tot].pos=m; a[tot].flag=-1; a[tot].h=h;
        }
    }
    sort(a+1,a+tot+1); m=nowm;
}
void modify(int p,int l,int r,int x,int y)
{
    if (l==r) {tree[p].t+=y; return;} int mid=(l+r)/2;
    if (x<=mid) modify(p*2,l,mid,x,y); else modify(p*2+1,mid+1,r,x,y);
    tree[p].t=tree[p*2].t+tree[p*2+1].t;
}
int ask(int p,int l,int r,int x)
{
    if (l==r) return (tree[p].t<x)?0:l; int mid=(l+r)/2,son=tree[p*2+1].t;
    if (x<=son) return ask(p*2+1,mid+1,r,x); else return ask(p*2,l,mid,x-son);
}
void solve()
{
    int last=0;
    for (int i=1,j=1; i<=tot; i=j)
    {
        int now=ask(1,1,m,limit); ans=ans+(long long)now*now*(a[i].pos-last);
        for (;(j<=tot)&&(a[j].pos==a[i].pos);j++) modify(1,1,m,a[j].h,a[j].flag);
        last=a[i].pos;
    }
    printf("%lld\n",ans);
}
int main()
{
    init();
    solve();
    return 0;
}

评论

暂无评论

发表评论

可以用@mike来提到mike这个用户,mike会被高亮显示。如果你真的想打“@”这个字符,请用“@@”。