zoukankan      html  css  js  c++  java
  • POJ 1151 / HDU 1542 Atlantis 线段树求矩形面积并

    题意:给出矩形两对角点坐标,求矩形面积并。

    解法:线段树+离散化。

    每加入一个矩形,将两个y值加入yy数组以待离散化,将左边界cover值置为1,右边界置为2,离散后建立的线段树其实是以y值建的树,线段树维护两个值:cover和len,cover表示该线段区间目前被覆盖的线段数目,len表示当前已覆盖的线段长度(化为离散前的真值),每次加入一条线段,将其y_low,y_high之间的区间染上line[i].cover,再以tree[1].len乘以接下来的线段的x坐标减去当前x坐标,即计算了一部分面积。

    如图情况,将会计算三次面积:

    代码:

    #include <iostream>
    #include <cmath>
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <cmath>
    #include <algorithm>
    #define eps 1e-8
    using namespace std;
    #define N 307
    
    struct node
    {
        int cov;
        double len;
    }tree[8*N];
    
    struct Line
    {
        double y1,y2,x;
        int cov;
    }line[2*N];
    double yy[2*N];
    
    int cmp(Line ka,Line kb)
    {
        return ka.x < kb.x;
    }
    
    int bsearch(int l,int r,double x)
    {
        while(l <= r)
        {
            int mid = (l+r)/2;
            if(fabs(yy[mid]-x) < eps)
                return mid;
            if(x > yy[mid])
                l = mid+1;
            else
                r = mid-1;
        }
        return l;
    }
    
    void build(int l,int r,int rt)
    {
        tree[rt].cov = 0;
        tree[rt].len = 0;
        if(l == r-1) return;
        int mid = (l+r)/2;
        build(l,mid,2*rt);
        build(mid,r,2*rt+1);
    }
    
    void pushup(int l,int r,int rt)
    {
        if(tree[rt].cov)
            tree[rt].len = yy[r]-yy[l];
        else if(l+1 == r)
            tree[rt].len = 0;
        else
            tree[rt].len = tree[2*rt].len + tree[2*rt+1].len;
    }
    
    void update(int l,int r,int aa,int bb,int cover,int rt)
    {
        if(aa <= l && bb >= r)
        {
            tree[rt].cov += cover;
            pushup(l,r,rt);
            return;
        }
        if(l+1 == r) return;
        int mid = (l+r)/2;
        if(aa <= mid)
            update(l,mid,aa,bb,cover,2*rt);
        if(bb > mid)
            update(mid,r,aa,bb,cover,2*rt+1);
        pushup(l,r,rt);
    }
    
    int main()
    {
        int n,m,cs = 1,i,j;
        double x1,y1,x2,y2;
        while(scanf("%d",&n)!=EOF && n)
        {
            m = 1;
            for(i=0;i<n;i++)
            {
                scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
                line[m].x = x1,line[m].y1 = y1,line[m].y2 = y2,line[m].cov = 1,yy[m++] = y1;
                line[m].x = x2,line[m].y1 = y1,line[m].y2 = y2,line[m].cov = -1,yy[m++] = y2;
            }
            m--;
            sort(yy+1,yy+m+1);
            int cnt = 2;
            for(i=2;i<=m;i++)
            {
                if(yy[i] != yy[i-1])
                    yy[cnt++] = yy[i];
            }
            cnt--;
            build(1,cnt,1);
            sort(line+1,line+m+1,cmp);
            double ans = 0.0;
            printf("Test case #%d
    ",cs++);
            for(i=1;i<m;i++)
            {
                int L = bsearch(1,cnt,line[i].y1);
                int R = bsearch(1,cnt,line[i].y2);
                update(1,cnt,L,R,line[i].cov,1);
                ans += tree[1].len*(line[i+1].x-line[i].x);
            }
            printf("Total explored area: %0.2lf
    
    ",ans);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    逻辑运算(二)
    Rust基础类型
    Rust简单demo
    逻辑基础(一)
    webpack配置typescript项目
    Go并发原理
    JS实现取任意类型的数组交集并集方法的思考
    JS 可逆加密的一种实现
    所有中文复姓
    将中文姓名转为拼音英文名的一种实现
  • 原文地址:https://www.cnblogs.com/whatbeg/p/3935119.html
Copyright © 2011-2022 走看看