一、内容

Atlantis

There are several ancient Greek texts that contain descriptions of the fabled island Atlantis. Some of these texts even include maps of parts of the island. But unfortunately, these maps describe different regions of Atlantis. Your friend Bill has to know the total area for which maps exist. You (unwisely) volunteered to write a program that calculates this quantity. 

Input

The input consists of several test cases. Each test case starts with a line containing a single integer n (1 <= n <= 100) of available maps. The n following lines describe one map each. Each of these lines contains four numbers x1;y1;x2;y2 (0 <= x1 < x2 <= 100000;0 <= y1 < y2 <= 100000), not necessarily integers. The values (x1; y1) and (x2;y2) are the coordinates of the top-left resp. bottom-right corner of the mapped area.
The input file is terminated by a line containing a single 0. Don't process it. 

Output

For each test case, your program should output one section. The first line of each section must be "Test case #k", where k is the number of the test case (starting with 1). The second one must be "Total explored area: a", where a is the total explored area (i.e. the area of the union of all rectangles in this test case), printed exact to two digits to the right of the decimal point.
Output a blank line after each test case. 

Sample Input

2
10 10 20 20
15 15 25 25.5
0

Sample Output

Test case #1
Total explored area: 180.00 

二、思路

  • 将图形的每个点进行离散化,因为坐标可能是小数。
  • 然后运用扫描线的算法,将每个矩形分成2条线段,分别是下面那条边,和上面那条边,然后对这些线段按照y坐标进行排序,当扫描到矩形下面那条线段,所在区间值就+1,扫当上面的线段,所在区间值-1。
    class Line implements Comparable<Line> {
       double l, r, h;
       int w;
       public Line(double l, double r, double h, int w) {
       	this.l = l;
       	this.r = r;
       	this.h = h;
       	this.w = w;
       }
       public int compareTo(Line o) {  //h就是y坐标 按照y坐标排序
       	return Double.compare(h, o.h);
       }
    }
    
  • 面积之和 = 当前的高度 * (区间 > 1的点的区间和)
    [Java] POJ - 1151线段树+扫描线_java[Java] POJ - 1151线段树+扫描线_leetcode_02
    [Java] POJ - 1151线段树+扫描线_java_03[Java] POJ - 1151线段树+扫描线_职场和发展_04
  • 最后每次输出一个Case都要打印一个换行

三、代码

import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.Scanner;

public class POJ_1151_扫描线 {
	static int n, cnt = 1;
	static int N = 105;
	static double x1, x2, y1, y2;
	static double[] X = new double[N << 1];
	static double[] len = new double[N << 4]; //因为有2N个点
	static int[] sum = new int[N << 4];
	static Line[] line = new Line[N << 1];
	static PrintWriter out = new PrintWriter(System.out);
	public static void main(String[] args) {
		Scanner sc = new Scanner(new  InputStreamReader(System.in));
		while (sc.hasNext()) {
			Arrays.fill(len, 0);
			Arrays.fill(sum, 0);
			n = sc.nextInt();
			if (n == 0) break;
			out.println("Test case #" + cnt++);
			for (int i = 1; i <= n; i++) {
				x1 = sc.nextDouble();
				y1 = sc.nextDouble();
				x2 = sc.nextDouble();
				y2 = sc.nextDouble();
				line[i * 2 - 1] = new Line(x1, x2, y1, 1);
				line[i * 2] = new Line(x1, x2, y2, -1);
				X[i * 2 - 1] = x1; 
				X[i * 2] = x2;
			}
			n <<= 1;
			Arrays.sort(X, 1, n | 1);
			Arrays.sort(line, 1, n | 1);
			//对X去重操作
			int tem = 0;
			X[0] = -1; //这步很关键
			for (int i = 1; i <= n; i++) {
				if (X[i] != X[tem]) {
					X[++tem] = X[i];
				}
			}
			double ans = 0;
			for (int i = 1; i < n; i++) {
				int l = low_bound(1, tem, line[i].l);  //二分查找当前值在线段树中代表的点
				int r = low_bound(1, tem, line[i].r);
				update(1, 1, tem - 1, l, r - 1, line[i].w);
				ans += len[1] * (line[i + 1].h - line[i].h);
			} 
			out.printf("Total explored area: %.2f\n\n", ans);
		}
		out.close();
	}
	static int low_bound(int l, int r, double x) {
		while (l < r){
            int mid = (l + r) >> 1;
            if(X[mid]>=x){
                r=mid;
            }else{
                l=mid+1;
            }
        }
        return l;
	}
	static void pushup(int id, int l, int r) {
		if(sum[id] > 0) {
			len[id] = X[r + 1] - X[l]; 
		}  else {
			len[id] = len[id << 1] + len[id << 1 | 1];
		}
	}
	static void update(int id, int l, int r, double x, double y, int v) {
		if (x <= l && r <= y) {
			//在这个区间
			sum[id] += v;
			pushup(id, l, r);
			return;
		}
		int mid = (l + r) >> 1;
		if (x <= mid) {
			update(id << 1, l, mid, x, y, v);
		}
		if (y > mid){
			update(id << 1 | 1, mid + 1, r, x, y, v);
		}
		pushup(id, l, r);
	}
}
class Line implements Comparable<Line> {
	double l, r, h;
	int w;
	public Line(double l, double r, double h, int w) {
		this.l = l;
		this.r = r;
		this.h = h;
		this.w = w;
	}
	public int compareTo(Line o) {
		return Double.compare(h, o.h);
	}
}