扫描线+离散化+线段树HDU1255&POJ1177

首先我们要对扫描线算法建立一个形象的认识,可以参考链接。大概就是,对于某个由多个矩形覆盖重叠形成的不规则几何体的面积,可以转化为从下往上一系列小矩形,有点像垒砖,层数为线段数-1,也就是矩形数*2-1。

在这个算法里,线段树维护整个区间被覆盖的,有效的“长”,它是由一小段一小段的线段组成,我们对于每条线段添加一个flag成员变量,当该线段被某矩形的下边包含,该线段flag+1,上边则-1。如果该线的flag大于0,则说明该线段在当前高度的有效的,就把它的len赋上它原本的长度,详细的可以看代码:

#include <cstdio>
#include <cstring>
#include <cctype>
#include <string>
#include <set>
#include <iostream>
#include <stack>
#include <cmath>
#include <queue>
#include <vector>
#include <algorithm>

using namespace std;

#define inf 0x3f3f3f3f
#define N 1100
#define ll long long
using namespace std;
#define lson(rt) rt<<1
#define rson(rt) rt<<1|1
struct Seg
{
    double l,r,h;
    int f;
    Seg() {}
    Seg(double a,double b,double c,int d):l(a),r(b),h(c),f(d) {}
    bool operator < (const Seg &cmp) const
    {
        return h<cmp.h;
    }
} e[N<<1];
struct node
{
    int l,r;
    int cnt;
    double len[2];
} t[N<<3];  //线段树
double X[N*2];
void build(int l, int r, int rt){
    t[rt].l=l;
    t[rt].r=r;
    t[rt].cnt=t[rt].len[0]=t[rt].len[1]=0;
    if(l==r)
        return;
    int m=(t[rt].l+t[rt].r)>>1;
    build(m+1,r,rson(rt));
    build(l,m,lson(rt));
}
void pushdown(int rt)
{
    if(t[rt].cnt)//当前的边被标记,就把当前的长度加上
        t[rt].len[0]=X[t[rt].r+1]-X[t[rt].l];
    else if(t[rt].l==t[rt].r)//当为一个点的时候长度为0
        t[rt].len[0]=0;
    else//其他情况把左右两个区间的值加上
        t[rt].len[0]=t[lson(rt)].len[0]+t[rson(rt)].len[0];

    if(t[rt].cnt>1){
        t[rt].len[1]=X[t[rt].r+1]-X[t[rt].l];
    }else if(t[rt].l==t[rt].r)
        t[rt].len[1]=0;
    else if(t[rt].cnt==1)
        t[rt].len[1]=t[lson(rt)].len[0]+t[rson(rt)].len[0];
    else
        t[rt].len[1]=t[lson(rt)].len[1]+t[rson(rt)].len[1];
}
void update(int l,int r,int rt,int val)
{   //l,r是现有线段,rt代表了待更新的区间
    if(t[rt].l==l&&t[rt].r==r)
    {
        t[rt].cnt+=val;//加上标记的值
        pushdown(rt);//向下更新节点
        return;
    }
    int m=(t[rt].l+t[rt].r)>>1;
    if(r<=m){
        update(l,r,lson(rt),val);
    }else if(l>m){
        update(l,r,rson(rt),val);
    }else{
        update(l,m,lson(rt),val);
        update(m+1,r,rson(rt),val);
    }
    pushdown(rt);
}
int T;
int main()
{
    int n;
    cin>>T;
    double a,b,c,d;
    while(T--)
    {
        scanf("%d",&n);
        int num=0;
        for(int i=0; i<n; i++)
        {
            scanf("%lf%lf%lf%lf",&a,&b,&c,&d);
            X[num]=a;
            e[num++]=Seg(a,c,b,1);//矩形下面用1来标记吗
            X[num]=c;
            e[num++]=Seg(a,c,d,-1);//上面用-1来标记
        }
        sort(X,X+num);//用于离散化
        sort(e,e+num);//把矩形的边的纵坐标从小到大排序
        int m=unique(X,X+num)-X;
        double ans=0;
        build(0,m-1,1);
        for(int i=0; i<num-1; 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,1,e[i].f);    //1是线段树的根,代表了解决区间是0~m-1,l~r是当前更新添加的线段
            ans+=t[1].len[1]*(e[i+1].h-e[i].h);
        }
        printf("%.2f\n",ans);
    }
    return 0;
}

至于poj1177,所求由面积并变为周长。稍微改变一下维护的值就好了。

#include<iostream>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<algorithm>
using namespace std;

#define N 5001

#define lson(rt) rt<<1
#define rson(rt) rt<<1|1

int pos[N][4];
int n;
struct node{
    int l,r;
    int len;
    int cnt;
    int sum;
    int lf,rf;
}t[N*4];

struct seg{
    int l,r;
    int h;
    int f;
    seg(){}
    seg(int a,int b,int c,int d):l(a),r(b),h(c),f(d){}
    bool operator<(seg x){
        return h<x.h;
    }
}e[N*2];

double dis[N*2];

void build(int rt,int l,int r){
    t[rt].l=l;
    t[rt].r=r;
    t[rt].sum=t[rt].len=t[rt].cnt=t[rt].lf=t[rt].rf=0;
    if(l==r){
        return;
    }
    int mid=(l+r)/2;
    build(lson(rt),l,mid);
    build(rson(rt),mid+1,r);
}
void pushdown(int rt){
    if(t[rt].cnt>0){
        t[rt].len=dis[t[rt].r+1]-dis[t[rt].l];
        t[rt].lf=t[rt].rf=1;
        t[rt].sum=2;
    }else if(t[rt].l==t[rt].r){
        t[rt].len=t[rt].sum=0;
        t[rt].lf=t[rt].rf=0;
    }else{
        t[rt].len=t[lson(rt)].len+t[rson(rt)].len;
        t[rt].sum=t[lson(rt)].sum+t[rson(rt)].sum;
        t[rt].lf=t[lson(rt)].lf;
        t[rt].rf=t[rson(rt)].rf;
        if(t[lson(rt)].rf==1&&t[rson(rt)].lf==1)
            t[rt].sum-=2;
    }
}
void update(int l,int r,int rt,int val){
    if(t[rt].l==l&&t[rt].r==r){
        t[rt].cnt+=val;
        pushdown(rt);
        return ;
    }
    int m=(t[rt].l+t[rt].r)/2;
    if(r<=m){
        update(l,r,lson(rt),val);
    }else if(l>m){
        update(l,r,rson(rt),val);
    }else{
        update(l,m,lson(rt),val);
        update(m+1,r,rson(rt),val);
    }
    pushdown(rt);
}
int main(){
    cin>>n;
    int ans=0;
    for(int i=0;i<n;i++){
        scanf("%d%d%d%d",&pos[i][0],&pos[i][1],&pos[i][2],&pos[i][3]);
    }
    for(int i=0;i<n;i++){
        e[2*i]=seg(pos[i][0],pos[i][2],pos[i][1],1);
        dis[2*i]=pos[i][0];
        e[2*i+1]=seg(pos[i][0],pos[i][2],pos[i][3],-1);
        dis[2*i+1]=pos[i][2];
    }
    sort(dis,dis+2*n);
    sort(e,e+n*2);
    int m=unique(dis,dis+2*n)-dis;
    build(1,0,m-1);
    int last=0;
    for(int i=0;i<2*n;i++){
        int l=lower_bound(dis,dis+m,e[i].l)-dis;
        int r=lower_bound(dis,dis+m,e[i].r)-dis-1;
        update(l,r,1,e[i].f);
        ans+=t[1].sum*(e[i+1].h-e[i].h);
        ans+=abs(last-t[1].len);
        last=t[1].len;
    }
    cout<<ans<<endl;
    return 0;
}

 

全部评论

相关推荐

我是小红是我:学校换成中南
点赞 评论 收藏
分享
评论
点赞
收藏
分享
牛客网
牛客企业服务