zoukankan      html  css  js  c++  java
  • 【面积并】 Atlantis

    传送门

    题意

    多组测试样例,n表示矩形的个数,每个矩形用左上角和右下角来描述,输出这些矩形的面积并,

    数据范围

    (egin{array}{l}1 leq n leq 10000 \ 0 leq x_{1}<x_{2} leq 100000 \ 0 leq y_{1}<y_{2} leq 100000end{array})

    题解

    一根扫描线从左到右或者从下到上扫描整个图形,在从左往右扫描的情况下,将每个矩形的始边和终边分别标记+1和-1,
    线段树对于所有y离散化后的个数范围建树,其中维护两个信息,当前扫描线覆盖的线段的个数、当前扫描线覆盖的线段的长度
    因为点是实数域的,所以接近无限,要对点离散化,用起点y1和终点(y2-1)来表示线段,线段树的结点标号就是离散后的下标。
    有一个四元组(( x_{1},y_{1},y_{2},+1))((x_{2},y_{1},y_{2},-1))分别标记矩形开始的边和结束的边
    不需要延迟标记,当前扫描线覆盖的长度都维护在根节点上。

    Code

    #include <bits/stdc++.h>
    #define pb push_back
    #define db double
    using namespace std;
    const int N = 100010;
    int n;
    struct Segment
    {
    	double x, y1, y2;
    	int k;
    	bool operator< (const Segment &t)const
    	{
    		return x < t.x;
    	}
    }seg[N * 2];
    struct Node
    {
    	int l, r;
    	int cnt;
    	double len;
    }tr[N * 8];
    
    vector<double> ys;
    int find(db y){
    	return lower_bound(ys.begin(),ys.end(),y)-ys.begin();
    }
    void push_up(int u)
    {
    	if (tr[u].cnt) tr[u].len = ys[tr[u].r + 1] - ys[tr[u].l];//当前区间有覆盖,加上当前区间代表线段的长度
    	else if (tr[u].l != tr[u].r)
    	{
    		tr[u].len = tr[u << 1].len + tr[u << 1 | 1].len;//将当前的总长度传递到根节点
    	}
    	else tr[u].len = 0;
    }
    void build(int u, int l, int r)
    {
    	tr[u] = {l, r, 0, 0};
    	if (l != r)
    	{
    		int mid = l + r >> 1;
    		build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r);
    	}
    }
    void change(int u,int l,int r,int k){
    	if(tr[u].l >= l && tr[u].r <= r){
    		tr[u].cnt += k;
    		push_up(u);
    	}
    	else {
    		int mid = tr[u].l + tr[u].r >> 1;
    		if( l <= mid ) change(u<<1,l,r,k);
    		if(r>mid) change(u<<1|1,l,r,k);
    		push_up(u);
    	}
    }
    int main(){
    	int T=1;
    	while(cin>>n,n){
    		ys.clear();
    		for(int i=0,j=0;i<n;i++){
    			double x1,y1,x2,y2;
    			cin>>x1>>y1>>x2>>y2;
    			ys.pb(y1);
    			ys.pb(y2);
    			seg[j++]={x1,y1,y2,1};
    			seg[j++]={x2,y1,y2,-1};
    		}
    		sort(ys.begin(),ys.end());
    		ys.erase(unique(ys.begin(),ys.end()),ys.end());
    		sort(seg,seg+2*n);
    		build(1,0,ys.size()-2);//线段个数比点的个数少1
    		
    		db res=0;
    		for(int i=0;i<n*2;i++){
    			if(i > 0) res += tr[1].len*(seg[i].x-seg[i-1].x);
    			change(1,find(seg[i].y1),find(seg[i].y2)-1,seg[i].k);
    		}
    		printf("Test case #%d
    ", T ++ );
    		printf("Total explored area: %.2lf
    
    ", res);
    	}
    }
    
  • 相关阅读:
    推荐一波好的代码托管
    二十一、如何导入svg图片
    二十、滑动开关css
    十九、CSS如何引入字体
    十八、移动端rem布局
    十五、css3 Filter--滤镜
    十四、css动画基础知识
    十三、初始化标签默认样式
    十二、移动端头部声明
    十一、使用a标签打电话、发短信、发邮件
  • 原文地址:https://www.cnblogs.com/hhyx/p/13700621.html
Copyright © 2011-2022 走看看