• HDU


    https://cn.vjudge.net/problem/HDU-1542

    题意

    求矩形的面积并

    分析

    点为浮点数,需要离散化处理。

    给定一个矩形的左下角坐标和右上角坐标分别为:(x1,y1)、(x2,y2),对这样的一个矩形,我们构造两条线段,一条定位在x1,它在y坐标的区间是[y1,y2],并且给定一个cover域值为1;另一条线段定位在x2,区间一样是[y1,y2],给定它一个cover值为-1。根据这样的方法对每个矩形都构造两个线段,最后将所有的线段根据所定位的x从左到右进行排序。插入某跟线段的时候,只要看该线段所在区间上的cover是否大于等于1,如果是,那么就可以将并面积值加上(目前线段的x定位 - 上一线段的x定位)*(该区间的大小)。

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <string>
    #include <algorithm>
    #include <cmath>
    #include <ctime>
    #include <vector>
    #include <queue>
    #include <map>
    #include <stack>
    #include <set>
    #include <bitset>
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    #define ms(a, b) memset(a, b, sizeof(a))
    #define pb push_back
    #define mp make_pair
    #define pii pair<int, int>
    #define eps 0.0000000001
    #define IOS ios::sync_with_stdio(0);cin.tie(0);
    #define random(a, b) rand()*rand()%(b-a+1)+a
    #define pi acos(-1)
    const ll INF = 0x3f3f3f3f3f3f3f3fll;
    const int inf = 0x3f3f3f3f;
    const int maxn = 2000 + 10;
    const int maxm = 200000 + 10;
    const int mod = 10007;
    
    int n;
    double y[maxn];
    struct LINE{
        double x;
        double y1,y2;
        int flag;
        bool operator <(const LINE &a)const{
            return x<a.x;
        }
    }line[maxn];
    struct ND{
        double l,r;
        double x;
        int cover;
        bool flag;
    }tree[maxn<<2];
    void build(int rt,int l,int r){
        tree[rt].l=y[l];
        tree[rt].r=y[r];
        tree[rt].x=-1;
        tree[rt].flag=false;
        tree[rt].cover=0; //表示该区间有多少线段,左加右减
        if(l+1==r){//叶结点
            tree[rt].flag=true;
            return;
        }
        int mid = (l+r)>>1;
        build(rt<<1,l,mid);
        build(rt<<1|1,mid,r);//这里是mid
    }
    double insert_query(int rt,double x,double l,double r,int flag){
        if(l>=tree[rt].r||r<=tree[rt].l) return 0; //检验区间合法
        if(tree[rt].flag){
            if(tree[rt].cover>0){
                double ans=(x-tree[rt].x)*(tree[rt].r-tree[rt].l);
                tree[rt].x=x;
                tree[rt].cover+=flag;
                return ans;
            }else{
                tree[rt].x=x;
                tree[rt].cover+=flag;
                return 0;
            }
        }
        return insert_query(rt<<1,x,l,r,flag)+insert_query(rt<<1|1,x,l,r,flag);
    }
    int main() {
    #ifdef LOCAL
        freopen("in.txt", "r", stdin);
    //    freopen("output.txt", "w", stdout);
    #endif
        int T,cas=1;
    //    scanf("%d",&T);
        while(~scanf("%d",&n)&&n){
            int cnt=-1;
            double x1,x2,y1,y2;
            for(int i=0;i<n;i++){
                scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
                y[++cnt]=y1;
                line[cnt].x=x1;
                line[cnt].y1=y1;
                line[cnt].y2=y2;
                line[cnt].flag=1;//左边
                y[++cnt]=y2;
                line[cnt].x=x2;
                line[cnt].y1=y1;
                line[cnt].y2=y2;
                line[cnt].flag=-1;//右边
            }
            sort(y,y+1+cnt);
            sort(line,line+1+cnt);
            build(1,0,cnt);
            double area=0;
            for(int i=0;i<=cnt;i++){
                area+=insert_query(1,line[i].x,line[i].y1,line[i].y2,line[i].flag);
            }
            printf("Test case #%d
    Total explored area: %.2f
    
    ",cas++,area);
        }
        return 0;
    }

    还有一种高端做法。

    该方法同样需要在线段树中定义一个cover域,表示该线段区间目前被覆盖的线段数目。另外再加一个len域,表示该区间可用于与下一线段求并面积的y坐标区间长度。然后利用简单的dp,将所有信息集中于tree[1].len上,这样便不用想第一种方法那样每次都求到叶子线段,大大节约了时间,并且代码也少了很多。

    #include<iostream>
    #include<string>
    #include<algorithm>
    using namespace std;
    
    struct node
    {
        int l;
        int r;
        int cover;
        double len;
    };
    
    node tree[2000];
    double yy[250];
    int n,len;
    
    struct Line
    {
        double y_down;
        double y_up;
        double x;
        int cover;
    };
    
    Line line[250];
    
    int cmp(Line a,Line b)
    {
        return a.x<b.x;
    }
    
    int find(double x)
    {
        int l=0,r=len,mid;
        while(l<=r)
        {
            mid=(l+r)/2;
            if(yy[mid]==x)
                return mid;
            if(yy[mid]<x)
                l=mid+1;
            else
                r=mid-1;
        }
        return l;
    }
    
    void build(int i,int l,int r)
    {
        tree[i].l=l;
        tree[i].r=r;
        tree[i].cover=0;
        tree[i].len=0;
        if(l+1==r)
            return;
        int mid=(l+r)/2;
        build(2*i,l,mid);
        build(2*i+1,mid,r);
    }
    
    void fun(int i)
    {
        if(tree[i].cover)
            tree[i].len=yy[tree[i].r]-yy[tree[i].l]; //如果cover大于1,那么整段都可用于与下一线段求并面积
        else if(tree[i].l+1==tree[i].r) //叶子线段
            tree[i].len=0;
        else
            tree[i].len=tree[2*i].len+tree[2*i+1].len; //很简单的dp
    }
    
    void updata(int i,int l,int r,int cover)
    {
        if(tree[i].l>r || tree[i].r<l)
            return;
        if(tree[i].l>=l && tree[i].r<=r)
        {
            tree[i].cover+=cover;
            fun(i);
            return;
        }
        updata(2*i,l,r,cover);
        updata(2*i+1,l,r,cover);
        fun(i);
    }
    
    int main()
    {
        double x1,y1,x2,y2;
        int i,m,a,b,cas=1;
        freopen("in.txt","r",stdin);
        while(scanf("%d",&n)==1 && n)
        {
            m=0;
            for(i=0;i<n;i++)
            {
                scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
                yy[m]=y1;
                line[m].cover=1;
                line[m].x=x1;
                line[m].y_down=y1;
                line[m++].y_up=y2;
    
                yy[m]=y2;
                line[m].cover=-1;
                line[m].x=x2;
                line[m].y_down=y1;
                line[m++].y_up=y2;
            }
            sort(yy,yy+m);
            len=1;
            for(i=1;i<m;i++)
            {
                if(yy[i-1]!=yy[i])
                    yy[len++]=yy[i];
            }
            len--;
            build(1,0,len);
            sort(line,line+m,cmp);
            double ans=0;
            printf("Test case #%d
    ",cas++);
            for(i=0;i<m-1;i++)
            {
                a=find(line[i].y_down);
                b=find(line[i].y_up);
                updata(1,a,b,line[i].cover);
                ans+=tree[1].len*(line[i+1].x-line[i].x);  //tree[1].len已经保留了整个树与line[i+1]所能求并面积的长度
            }
            printf("Total explored area: %0.2lf
    
    ",ans);
        }
        return 0;
    }
  • 相关阅读:
    github常用项目汇总
    javaweb Servlet接收Android请求,并返回json数据
    Hibernate 工具类
    JDBC 工具类
    050 Android 百度地图的使用
    Hibernate 连接数据库,数据库返回数据超过限制报错
    049 Android Fragment向另一个Activity传值
    java 实用Util汇总
    关于The requested PHP extension ext-pdo_sqlite * is missing from your system. Install or enable PHP's pdo_sqlite extension.的解决
    Symfony命令大全
  • 原文地址:https://www.cnblogs.com/fht-litost/p/9580330.html
Copyright © 2020-2023  润新知