• HDU 1828 线段树+扫描线(计算矩形周长并)


    题意:给你n个矩形,然后矩形有可能重叠,要你求周长

    思路:首先碰到这种矩形在数轴上那么第一反应应该想到的是扫描线,

    做周长我们有两种方法

    第一种,我们可以分开两部分求,第一遍求x轴上的贡献,第二遍求y轴上的贡献

    首先第一条边我们可以直接加出贡献,第二条边我们和第一条有覆盖部分,那么我们要怎么加呢,我们会发现要加的也就是  ( 加入这条边后的线段树上最大长度-没加之前的最大长度)

    然后我们再加进来,会看到加入出边的时候因为是-1了,所以加入后的长度会比没加之前的值小,但是贡献依然是他们的差值,那么我们就只要求绝对值即可

    y轴上是一样的道理

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<iostream>
    #include<cstdlib>
    #include<algorithm>
    #define mem(a,b) memset(a,b,sizeof(a))
    #define inf 0x3f3f3f3f
    #define N 10005
    #define ll long long
    using namespace std;
    #define lson l,m,rt<<1
    #define rson m+1,r,rt<<1|1
    struct Seg
    {
        int l,r,h;
        int f;
        Seg() {}
        Seg(int a,int b,int c,int d):l(a),r(b),h(c),f(d) {}
        bool operator < (const Seg &cmp) const
        {
            return h<cmp.h;
        }
    } e[N],e2[N];
    struct node
    {
        int cnt;
        int len;
    } t[N<<2];
    int X[N];
    int Y[N]; 
    void pushdown(int l,int r,int rt,int X[])
    {
        if(t[rt].cnt)//当前的边被标记,就把当前的长度加上
            t[rt].len=X[r+1]-X[l];
        else if(l==r)//当为一个点的时候长度为0
            t[rt].len=0;
        else//其他情况把左右两个区间的值加上
            t[rt].len=t[rt<<1].len+t[rt<<1|1].len;
    }
    void update(int L,int R,int l,int r,int rt,int val,int X[])
    {
        if(L<=l&&r<=R)
        {
            t[rt].cnt+=val;//加上标记的值
            pushdown(l,r,rt,X);//像下更新节点
            return;
        }
        int m=(l+r)>>1;
        if(L<=m) update(L,R,lson,val,X);
        if(R>m) update(L,R,rson,val,X);
        pushdown(l,r,rt,X);
    }
    int main()
    {
        int n;
        int a,b,c,d;
        while(scanf("%d",&n)!=EOF)
        {
            mem(t,0);
            int num=0;
            for(int i=0; i<n; i++)
            {
                scanf("%d%d%d%d",&a,&b,&c,&d);
                X[num]=a;Y[num]=b;
                e[num]=Seg(a,c,b,1);//矩形下面用1来标记吗
                e2[num++]=Seg(b,d,a,1);
                X[num]=c;Y[num]=d;
                e[num]=Seg(a,c,d,-1);//上面用-1来标记
                e2[num++]=Seg(b,d,c,-1);
            }
            sort(Y,Y+num);
            sort(X,X+num);//用于离散化
            sort(e,e+num);//把矩形的边的纵坐标从小到大排序
            sort(e2,e2+num);
            int m=unique(X,X+num)-X;
            int m2=unique(Y,Y+num)-Y;
            int ans=0;
            int last=0; 
            for(int i=0; i<num; i++)
            {
                int l=lower_bound(X,X+m,e[i].l)-X;//找出离散化以后的值
                int r=lower_bound(X,X+m,e[i].r)-X-1;
                update(l,r,0,m,1,e[i].f,X);
                ans+=abs(last-t[1].len);
                last=t[1].len;
            }
            last=0; 
            memset(t,0,sizeof(t));
            for(int i=0; i<num; i++)
            {
                int l=lower_bound(Y,Y+m2,e2[i].l)-Y;//找出离散化以后的值
                int r=lower_bound(Y,Y+m2,e2[i].r)-Y-1;
                update(l,r,0,m2,1,e2[i].f,Y);
                ans+=abs(last-t[1].len);
                last=t[1].len;
            }
            printf("%d
    ",ans);
        }
        return 0;
    }

    第二种我暂时不会,先空着,只要求一遍扫描线

  • 相关阅读:
    整合Sleuth
    idea springboot 微服务批量启动
    思维的八层境界(深度好文)
    【格局视野】三色需求与工作层次
    【阅读推荐】改变你思维模式的书单
    【软件架构】七款代码味道识别工具
    【软件架构】代码重构之道
    【Android】EventBus 源码解析
    【软件架构】IM架构设计(安卓版)
    【设计模式】Java版设计模式的类图汇总
  • 原文地址:https://www.cnblogs.com/Lis-/p/11279380.html
Copyright © 2020-2023  润新知