• POJ 1151 Atlantis 求矩阵面积并 扫描线 具体解释


    题意:

    给定n个矩阵的左下角和右上角坐标,求矩阵面积并(矩阵总是正放的,即与x轴y轴都平行)

    思路:

    扫描线裸题

    http://www.cnblogs.com/fenshen371/p/3214092.html

    对于一个矩阵,我们仅仅关心他的上下底边。线段树维护的是当前有哪些区间是被线段覆盖的(即把线段都移动到x轴上,x轴被覆盖的长度是多少)

    我们从上往下扫,则对于随意一条(如15,10)  我们会计算(20,13)-(15,10)之间的矩形面积

    而对于(11,8),我们会计算(15,10)-(11,8)之间的矩形面积。

    矩形面积= 底边长*高

    1、显然这里的高就是(15,10)-(11,8) ; 更通俗的就是:line[i-1].y - line[i].y;

    2、而底边长则是取决于从(11,8) 向上(不包含(11,8))有多长的区间被线段覆盖了,这个长度则是用线段树来维护。

    3、而(11,8)这条线段对于线段树或者说 对区间是覆盖还是删除则取决于这条线段是上底边还是下底边(上底边则是覆盖,下底边则是删除)


    对于线段树的建树也要注意一个要点:

    平时建树的习惯是:

    [1,4] 

    /

    [1,2]    [3,4]

    而我们用线段树维护的是x轴坐标,是连续的区间,假设这样建树则忽略掉了区间[2,3]

    所以我们建成如此:

          [1,4]

    /

    [1,2] [2,4]

    即: build(l,mid,L(id)); build(mid,r,R(id)); mid不+1了

    推断某区间是否为最底层区间时则写成 if(tree[id].l +1 == tree[id].r) ;

    由于[1,1]这个区间对我们是没有意义的,即 l < r才是有长度的区间,才是有意义的。而最小的l < r 就是 l +1 = r 的情况。

    代码:

    #include <stdio.h>
    #include <string.h>
    #include <iostream>
    #include <algorithm>
    #include <queue>
    #include <set>
    #include <map>
    using namespace std;
    #define N 205
    #define L(x) (x<<1)
    #define R(x) (x<<1|1)
    int Mid(int a,int b){return (a+b)>>1;}
    //这份代码是对y轴建树,从左到右扫
    struct node{ //这个区间被c条线段覆盖了
    	int l, r;
    	int c;  //用来记录重叠情况
    	double cnt, lf, rf;//离散点l相应的实际点lf cnt表示这个区间内存在的线段长度
    }tree[N*4];
    struct Line{
    	double x,y1,y2;
    	int f;
    	Line(double a=0.0,double b=0.0,double c=0.0, int d=0):x(a),y1(b),y2(c),f(d){}
    }line[N*2];
    bool cmp(Line a, Line b){return a.x<b.x;}
    double y[N];
    void build(int l, int r, int id){
    	tree[id].l = l, tree[id].r = r;
    	tree[id].cnt = tree[id].c = 0;
    	tree[id].lf = y[l]; tree[id].rf = y[r];
    	if(l+1==r)return ;
    	int mid = Mid(l,r);
    	build(l, mid, L(id));
    	build(mid,r,R(id));
    }
    void push_up(int id){
    	if(tree[id].c){
    		tree[id].cnt = tree[id].rf - tree[id].lf;
    		return ;
    	}
    	if(tree[id].l+1 == tree[id].r) tree[id].cnt = 0;
    	else tree[id].cnt = tree[L(id)].cnt + tree[R(id)].cnt;
    }
    void update(int id, Line e){
    	if(e.y1 == tree[id].lf && tree[id].rf == e.y2){
    		tree[id].c += e.f;
    		push_up(id);	return ;
    	}
    	if(e.y2 <= tree[L(id)].rf)
    		update(L(id),e);
    	else if(tree[R(id)].lf <= e.y1)
    		update(R(id),e);
    	else {
    		Line tmp = e;	tmp.y2 = tree[L(id)].rf;	update(L(id),tmp);
    		tmp = e;		tmp.y1 = tree[R(id)].lf;	update(R(id),tmp);
    	}
    	push_up(id);
    }
    set<double>myset;
    set<double>::iterator p;
    int main(){
    	int i, j, n, Cas = 1;
    	double x1,x2,y1,y2;
    	while(scanf("%d",&n),n){
    		myset.clear();
    		int top = 1;
    		for(i = 1;i <= n; i++){
    			scanf("%lf %lf %lf %lf",&x1,&y1,&x2,&y2);
    			myset.insert(y1); myset.insert(y2);
    			Line E = Line(x1,y1,y2,1);
    			line[top++] = E;
    			Line E2= Line(x2,y1,y2,-1);
    			line[top++] = E2;
    		}
    		sort(line+1, line+top, cmp);
    		int siz = 1;
    		for(p=myset.begin(); p!=myset.end(); p++)	y[siz++] = *p;
    		build(1, siz-1, 1);
    		update(1, line[1]);
    		double ans = 0;
    		for(i = 2; i < top; i++){
    			ans += tree[1].cnt * (line[i].x - line[i-1].x);
    			update(1, line[i]);
    		}
    		printf("Test case #%d
    Total explored area: %.2lf
    
    ",Cas++,ans);
    	}
    	return 0;
    }
    


  • 相关阅读:
    jquery swipper插件的一些弊端
    linux ffmpeg 源码安装教程
    二叉树遍历(宽度优先)入门
    node安装教程
    Check the string CodeForces
    Minimize the error CodeForces
    sourcestress 问题解决方案
    C++ substr
    Java 读取Excel文件
    Stall Reservations
  • 原文地址:https://www.cnblogs.com/zfyouxi/p/3774930.html
Copyright © 2020-2023  润新知