hdu1255 覆盖的面积

本文详细介绍了线段树和线扫描相结合的算法应用,通过实例展示了如何利用这种组合来解决特定问题,包括算法实现、关键步骤解释及实际应用场景分析。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

典型的线段树+线扫描
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#include<math.h>
using namespace std;
#define nn 1010

struct node
{
    int l,r,c;
    double len1,len2;
}tree[nn<<3];
struct seg
{
    double l,r,h;
    int f;
}s[nn<<1];
double pos[nn<<1];

bool cmp(seg a,seg b)
{
    return a.h<b.h;
}
int binary(double c,int low,int top)
{
    while(low<=top)
    {
        int mid=(low+top)>>1;
        if(pos[mid]==c)     return mid;
        else if(pos[mid]>c)   top=mid;
        else low=mid+1;
    }
    return -1;
}
void build(int ll,int rr,int rt)
{
    tree[rt].l=ll;  tree[rt].r=rr;  tree[rt].c=0;
    if(ll==rr)  return;
    int mid=(ll+rr)>>1;
    build(ll,mid,rt<<1);
    build(mid+1,rr,rt<<1|1);
}
void getlen(int rt)
{
    if(tree[rt].c)
        tree[rt].len1=pos[tree[rt].r+1]-pos[tree[rt].l];
    else if(tree[rt].r==tree[rt].l)
        tree[rt].len1=0;
    else
        tree[rt].len1=tree[rt<<1].len1+tree[rt<<1|1].len1;

    if(tree[rt].c>=2)
        tree[rt].len2=pos[tree[rt].r+1]-pos[tree[rt].l];
    else if(tree[rt].r==tree[rt].l)
        tree[rt].len2=0;
    else if(tree[rt].c==1)//如果该点被更新一次,则等于儿子被更新一次以上的长度和;
        tree[rt].len2=tree[rt<<1].len1+tree[rt<<1|1].len1;
    else
        tree[rt].len2=tree[rt<<1].len2+tree[rt<<1|1].len2;
}
void updata(int ll,int rr,int v,int rt)
{
    if(tree[rt].l==ll && tree[rt].r==rr)
    {
        tree[rt].c+=v;
        getlen(rt);
        return;
    }
    int mid=(tree[rt].l+tree[rt].r)>>1;
    if(rr<=mid)
        updata(ll,rr,v,rt<<1);
    else if(ll>mid)
        updata(ll,rr,v,rt<<1|1);
    else
    {
        updata(ll,mid,v,rt<<1);
        updata(mid+1,rr,v,rt<<1|1);
    }
    getlen(rt);
}
int main()
{
    int t,n,m;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        int num=0;
        for(int i=0;i<n;i++)
        {
            double x1,x2,y1,y2;
            scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
            s[num].l=x1;    s[num].r=x2;    s[num].h=y1;    s[num].f=1;
            s[num+1].l=x1;    s[num+1].r=x2;    s[num+1].h=y2;    s[num+1].f=-1;
            pos[num]=x1;    pos[num+1]=x2;
            num+=2;
        }
        sort(pos,pos+num);
        sort(s,s+num,cmp);
        int m=1;
        for(int i=1;i<num;i++)
            if(pos[i]!=pos[i-1])
                pos[m++]=pos[i];
        /*for(int i=0;i<m;i++)
            printf("%.2lf ",pos[i]);
        printf("\n");
        for(int i=0;i<num;i++)
            printf("%.2lf %.2lf %.2lf\n",s[i].l,s[i].r,s[i].h);
        printf("\n");*/
        build(0,m-1,1);
        double ans=0.0;
        for(int i=0;i<num;i++)
        {
            int l=binary(s[i].l,0,m-1);
            int r=binary(s[i].r,0,m-1)-1;
            //printf("%d %d\n",l,r);
            updata(l,r,s[i].f,1);
            //printf("A\n");
            ans+=(s[i+1].h-s[i].h)*tree[1].len2;
            //printf("%.2lf\n",tree[1].len2);
        }
        printf("%.2lf\n",ans);
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值