码迷,mamicode.com
首页 > 其他好文 > 详细

计算直角坐标系的面积并和面积交(可小数)

时间:2020-02-20 15:09:23      阅读:87      评论:0      收藏:0      [点我收藏+]

标签:lis   main   完全   isa   分时   algorithm   isp   efi   一点   

面积并

3个要素:1、离散化,因为坐标可以是浮点数,有些题可能距离很长

      2、扫描线,将每个矩形的俩条平行与x轴的俩条边存到数组里,标记为上边和下边,每次扫描到下边的时候,就将这一段统计起来,扫描到下边的时候就将之前的统计去掉;

      3、线段树,管理矩形的这些边在x轴方向上的有效距离,实际操作就把这些边一段一段地加到线段树上;

注意:线段树的每一个叶子节点点比如tree[L]维护的是的是区间(x[L],x[L+1]),线段树的其他节点例如(L,R)维护的是区间(x[L],x[R+1]);

cnt是记录当前区间有无被覆盖,要是扫描到下边界的话,这个合法区间的cnt就++,扫描到上边界的话就--;

题:http://acm.hdu.edu.cn/showproblem.php?pid=1542

技术图片
#include <algorithm>
#include <cctype>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <string>
#include <set>
#include <vector>

using namespace std;
#define pb push_back
const int M=205;
struct node{
    double l,r,h;
    int flag;
    node(double ll=0,double rr=0,double hh=0,int fl=0):l(ll),r(rr),h(hh),flag(fl){}
    bool operator <(const node &b)const{
        return h<b.h;
    }
}a[M];
struct TREE{
    double sum;
    int cnt;
}tree[M<<2];
double lisan[M];
void up(int root,int l,int r){
    if(tree[root].cnt)
        tree[root].sum=lisan[r+1]-lisan[l];
    else if(l==r)
        tree[root].sum=0;
    else
        tree[root].sum=tree[root<<1].sum+tree[root<<1|1].sum;
}
void update(int L,int R,int v,int root,int l,int r){
    if(L<=l&&r<=R){
        tree[root].cnt+=v;
        up(root,l,r);
        return ;
    }
    int midd=(l+r)>>1;
    if(L<=midd)
        update(L,R,v,root<<1,l,midd);
    if(R>midd)
        update(L,R,v,root<<1|1,midd+1,r);
    up(root,l,r);///上传到tree【1】 
}
int main(){
    int t=1,n;
    while(scanf("%d",&n)==1&&n){
        for(int i=0;i<=4*n;i++)
            tree[i].cnt=0,tree[i].sum=0;
        for(int i=1;i<=n;i++){
            double x1,y1,x2,y2;
            scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
            lisan[i]=x1;
            lisan[i+n]=x2;
            a[i]=node(x1,x2,y1,1);
            a[i+n]=node(x1,x2,y2,-1);
        }
         
        sort(lisan+1,lisan+1+2*n);
        sort(a+1,a+1+2*n);
        
        int m=unique(lisan+1,lisan+1+2*n)-lisan-1;
        double ans=0;
        for(int i=1;i<2*n;i++){
            int l=lower_bound(lisan+1,lisan+1+m,a[i].l)-lisan;
            int r=lower_bound(lisan+1,lisan+1+m,a[i].r)-lisan;
            if(l<r)///每个节点控制的是区间(lisan[i],lisan[i+1]) 
            ///区间[lisan[l],lisan[r+1]]对应的原本区间即为(l,r-1); 
                update(l,r-1,a[i].flag,1,1,m);
            ans+=(a[i+1].h-a[i].h)*tree[1].sum;
        }
        printf("Test case #%d\n",t++);
        printf("Total explored area: %.2f\n\n",ans);
    }
    return 0;
}
View Code

 

面积交:

分析:实际上这个问题就是问被覆盖俩次及以上的面积是多少,所以我们只要再原基础上再记录一个覆盖俩次的标记长度two,接下来就是分析怎么更新这个two;

   要明确一点,就是cnt是实际有意义的,不想lazy值那样是传递的,所以分类讨论一下:

   1、当cnt为0时,表示当前区间没有被完全覆盖,那么覆盖一次和覆盖俩次的长度只能由他们的儿子决定;

   2、当cnt为1时,表示当前区间被完全覆盖过一次,那么覆盖一次的长度就等于x[R+1]-x[L],而覆盖俩次及以上的部分时完全覆盖一次和这个区间儿子覆盖部分的交集,所以只要算儿子覆盖一次带来的贡献即可;

   3,当cnt为2时,表示当前区间被完全覆盖过俩次,覆盖一次和覆盖俩次的长度就为覆盖一次和覆盖俩次的长度;

题:http://acm.hdu.edu.cn/showproblem.php?pid=1255

技术图片
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int M=2e3+3;
struct node{
    double l,r,h;
    int flag;
    node(double ll=0,double rr=0,double hh=0,int fl=0):l(ll),r(rr),h(hh),flag(fl){}
    bool operator <(const node &b)const{
        return h<b.h;
    }
}a[M];
struct TREE{
    double two,one;
    int cnt;
}tree[M<<2];
double lisan[M];
void up(int root,int l,int r){
    if(tree[root].cnt>=2)
        tree[root].two=tree[root].one=lisan[r+1]-lisan[l];
    else if(tree[root].cnt==1){
        tree[root].one=lisan[r+1]-lisan[l];
        if(l==r)
            tree[root].two=0;
        else
            tree[root].two=tree[root<<1].one+tree[root<<1|1].one;
    } 
    else{
        if(l==r)
            tree[root].one=tree[root].two=0;
        else{
            tree[root].one=tree[root<<1].one+tree[root<<1|1].one; 
            tree[root].two=tree[root<<1].two+tree[root<<1|1].two;
        }
        
    }
}
void update(int L,int R,int v,int root,int l,int r){
    if(L<=l&&r<=R){
        tree[root].cnt+=v;
        up(root,l,r);
        return ;
    }
    int midd=(l+r)>>1;
    if(L<=midd)
        update(L,R,v,root<<1,l,midd);
    if(R>midd)
        update(L,R,v,root<<1|1,midd+1,r);
    up(root,l,r);///上传到tree【1】 
}
int main(){
    int t,n;
    scanf("%d",&t);
    while(t--){
        scanf("%d",&n);
    
        for(int i=1;i<=n;i++){
            double x1,y1,x2,y2;
            scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
            lisan[i]=x1;
            lisan[i+n]=x2;
            a[i]=node(x1,x2,y1,1);
            a[i+n]=node(x1,x2,y2,-1);
        }
        n<<=1; 
        sort(lisan+1,lisan+1+n);
        sort(a+1,a+1+n);
        memset(tree,0,sizeof(tree));
        int m=unique(lisan+1,lisan+1+n)-lisan-1;
        double ans=0;
        for(int i=1;i<n;i++){
            int l=lower_bound(lisan+1,lisan+1+m,a[i].l)-lisan;
            int r=lower_bound(lisan+1,lisan+1+m,a[i].r)-lisan;
            if(l<r)///每个节点控制的是区间(lisan[i],lisan[i+1]) 
            ///区间[lisan[l],lisan[r+1]]对应的原本区间即为(l,r-1); 
                update(l,r-1,a[i].flag,1,1,m);
            ans+=(a[i+1].h-a[i].h)*tree[1].two;
        }
        printf("%.2f\n",ans);
    }
    return 0;
}
View Code

 

计算直角坐标系的面积并和面积交(可小数)

标签:lis   main   完全   isa   分时   algorithm   isp   efi   一点   

原文地址:https://www.cnblogs.com/starve/p/12335386.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!