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 C (judge verdict: Accepted)

#include <stdio.h>
#include <string.h>

typedef struct {
    int sx, sy;
    int ex, ey;
} RECT;

int min(int a, int b)
{
    return (b > a ? a : b);
}

int max(int a, int b)
{
    return (a > b ? a : b);
}

int comp(const void *a, const void *b)
{
    RECT x, y;
    x = *(RECT *)a;
    y = *(RECT *)b;
    
    return (x.sx - y.sx);
}

int comp_int(const void *a, const void *b)
{
    int x, y;
    x = *(int *)a;
    y = *(int *)b;
    
    return (x - y);
}

int area;
int length;

RECT calc[10000];
RECT before[10000];
int bsize;

void mergeArea(RECT *grid, int n, int *sq)
{
    int i, j;
    int num;
    int start, end;
    
    if (n == 0){
        return;
    }
    num = 0;
    start = grid[0].sx;
    end = grid[0].ex;
    for (i = 1; i < n; i++){
        if (grid[i].sx <= end){
            end = max(end, grid[i].ex);
        }
        else {
            calc[num].sx = start;
            calc[num++].ex = end;
            start = grid[i].sx;
            end = grid[i].ex;
        }
    }
    calc[num].sx = start;
    calc[num++].ex = end;
    for (i = 0; i < num; i++){
        area += calc[i].ex - calc[i].sx;
    }
    
    *sq = num;
}

void mergeLength(RECT *grid, int n)
{
    int total[40000];
    int i;
    int res, num;
    
    num = 0;
    for (i = 0; i < n; i++){
        total[num++] = grid[i].sx;
        total[num++] = grid[i].ex;
    }
    for (i = 0; i < bsize; i++){
        total[num++] = before[i].sx;
        total[num++] = before[i].ex;
    }
    
    qsort(total, num, sizeof(int), comp_int);
    res = 0;
    for (i = 0; i < num; i += 2){
        res += total[i + 1] - total[i];
    }
    length += res + 2 * n;
}

int main(void)
{
    int n, query;
    static RECT p[10000];
    static RECT grid[10000];
    int num;
    int i, j;
    int sq;
    int miny, maxy;
    
    while (1){
        scanf("%d%d", &n, &query);
        
        if (n + query == 0){
            break;
        }
        area = length = 0;
        miny = 1000000;
        maxy = -100000;
        for (i = 0; i < n; i++){
            scanf("%d%d%d%d", &p[i].sx, &p[i].sy, &p[i].ex, &p[i].ey);
            miny = min(miny, p[i].sy);
            maxy = max(maxy, p[i].ey);
        }
        bsize = 0;
        memset(before, 0, sizeof(before));
        qsort(p, n, sizeof(RECT), comp);
        area = length = 0;
        for (i = miny; i <= maxy; i++){
            memset(grid, 0, sizeof(grid));
            num = sq = 0;
            for (j = 0; j < n; j++){
                if (p[j].sy <= i && i < p[j].ey){
                    grid[num++] = p[j];
                }
            }
            mergeArea(grid, num, &sq);
            if (query == 2 && (bsize != 0 || num != 0)){
                mergeLength(calc, sq);
            }
            memcpy(before, calc, sizeof(calc));
            bsize = sq;
        }
        printf("%d\n", area);
        if (query == 2){
            printf("%d\n", length);
        }
    }
    
    return (0);
}