Problem:
平面に長方形のシートが何枚か置かれている. これらのシートで覆われている部分の面積や周長を求めるプログラムを作成せよ.

ただし, 平面を座標平面とみなしたとき, シートの配置は次の条件 (1), (2) を満たすものとする.

(1) 各シートの長方形の 4 頂点の x, y 座標は全て 0 以上 10000 以下の整数であり, 長方形の各辺は x 軸, または y 軸に平行である.

(2) シートの枚数は高々 10000 枚以下である.

入力データ の 1 行目に長方形の個数 n と問題の種類を表す整数 r が空白で区切って書かれている. 2 行目以降の各行には, 各シートの左下頂点座標 (x1, y1) と右上頂点座標 (x2, y2) の座標値が x1, y1, x2, y2 の順で空白で区切って書いてある.

出力には r = 1 のとき 1 行目に面積を, r = 2 のとき 1 行目に面積, 2 行目に周囲の長さを出力する. いずれの場合も最後に改行を入れること.

また, テストデータの 40% では長方形の頂点の座標が 0 以上 100 以下で, そのうちの 1/2 では面積だけを求める問題である. さらに, 全体の 1/2 は面積だけを求める問題である.

入力例１

入力例２

入力例３

入力例４

5 1

5 2

2 2

3 2

0 0 3 2

0 0 3 2

0 0 8 9

2 2 8 8

1 1 2 5

1 1 2 5

0 0 9 8

3 0 4 9

0 4 6 5

0 4 6 5

5 0 7 9

3 3 5 6

3 3 5 6

5 0 7 6

5 0 7 6

　

出力例１

出力例２

出力例３

出力例４

29

29

80

45

38

36

36

入力

入力は複数のデータセットからなる．n, r がともに 0 のとき入力が終了する．データセットの数は 10 を超えない．

出力

データセットごとに, r = 1 のとき 1 行目に面積を, r = 2 のとき 1 行目に面積, 2 行目に周囲の長さを出力する.

入力例

5 1
0 0 3 2
1 1 2 5
0 4 6 5
3 3 5 6
5 0 7 6
5 2
0 0 3 2
1 1 2 5
0 4 6 5
3 3 5 6
5 0 7 6
2 2
0 0 8 9
0 0 9 8
3 2
2 2 8 8
3 0 4 9
5 0 7 9
0 0

出力例

29
29
38
80
36
45
36

上記問題文と自動審判に使われるデータは、情報オリンピック日本委員会が作成し公開している問題文と採点用テストデータです。

Solution in JAVA (judge verdict: Accepted)

import java.util.*;

class Plane {
  public Plane() {
    plane = new ArrayList<Strip>();
    for(int i = 0; i < MAX; i++) plane.add(new Strip());
  }

  public void cover(int x1, int y1, int x2, int y2) {
    for(int i = x1; i < x2; i++) {
      plane.get(i).cover(y1, y2);
    }
  }

  public int area() {
    int area = 0;
    for(Strip s : plane) area += s.area();
    return area;
  }

  public int girth() {
    Strip border = new Strip();
    Strip prev = border;

    int girth = 0;

    for(Strip s : plane) {
      girth += s.girth(prev);
      prev = s;
    }

    girth += border.girth(prev);

    return girth;
  }

  private List<Strip> plane;
  private static final int MAX = 10000;
}

class Strip {
  public void cover(int x, int y) {
    ListIterator<Range> iter = ranges.listIterator(0);
    while(iter.hasNext()) {
      Range r = iter.next();

      int a = r.getStart();
      int b = r.getEnd();

      if(a <= x && y <= b) return;
      else if(x <= a && b <= y) iter.remove();
      else if(a <= x && x <= b) {
        iter.remove();
        x = a;
      }
      else if(x <= a && a <= y) {
        iter.remove();
        y = b;
      }
      else if(y < a) {
        iter.previous();
        iter.add(new Range(x, y));
        return;
      }
    }

    ranges.add(new Range(x, y));
  }

  public int area() {
    int area = 0;
    for(Range r : ranges) area += r.length();
    return area;
  }

  public int girth(Strip left) {
    int girth = 0;

    for(Range r : ranges) girth += 2;

    int cur = 0;

    while(true) {
      Range l = left.getNearestRange(cur);
      Range r = this.getNearestRange(cur);

      if(l == null && r == null) break;
      else if(l == null) {
        if(cur < r.getStart()) cur = r.getStart();
        girth += r.getEnd() - cur;
        cur = r.getEnd();
      }
      else if(r == null) {
        if(cur < l.getStart()) cur = l.getStart();
        girth += l.getEnd() - cur;
        cur = l.getEnd();
      }
      else {
        int ls = l.getStart();
        int rs = r.getStart();
        int le = l.getEnd();
        int re = r.getEnd();

        if(ls <= rs) {
          cur = Math.max(ls, cur);

          if(le <= rs) {
            girth += le - cur;
            cur = le;
          }
          else {
            girth += rs - cur;
            cur = Math.min(le, re);
          }
        }
        else if(rs <= ls) {
          cur = Math.max(rs, cur);

          if(re <= ls) {
            girth += re - cur;
            cur = re;
          }
          else {
            girth += ls - cur;
            cur = Math.min(le, re);
          }
        }
      }
    }

    return girth;
  }

  private Range getNearestRange(int pos) {
    for(Range r : ranges) {
      if(r.getEnd() > pos) return r;
    }

    return null;
  }

  private List<Range> ranges = new LinkedList<Range>();
}

class Range {
  public Range(int a, int b) {
    this.a = a;
    this.b = b;
  }

  public int length() {
    return b - a;
  }

  public int getStart() {
    return a;
  }

  public int getEnd() {
    return b;
  }

  private int a;
  private int b;
}

public class Main {
  private Scanner sc = new Scanner(System.in);

  public void run() {
    while(sc.hasNextInt()) {
      int n = sc.nextInt();
      int r = sc.nextInt();

      if(n == 0 && r == 0) break;

      Plane plane = new Plane();
      for(int i = 0; i < n; i++) {
        plane.cover(sc.nextInt(), sc.nextInt(), sc.nextInt(), sc.nextInt());
      }

      System.out.println(plane.area());

      if(r == 2) System.out.println(plane.girth());
    }
  }

  public static void main(String[] args) {
    new Main().run();
  }
}