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;
}

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

原文地址:https://www.cnblogs.com/Lis-/p/11279380.html