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

class LazySegmentTree
	def initialize(n, l = 0, r = n-1)
		@range_min = l
		@range_max = r
		@start = 0
		@between = 0
		@end = 0
		if l == r
		else
			c = (l + r) / 2
			@left_child = self.class.new(n, l, c)
			@right_child = self.class.new(n, c+1, r)
		end
	end

	attr_reader :range_min, :range_max

	def add_start(x, bits)
		if @range_min == @range_max
			@start |= bits
		else
			if x <= @left_child.range_max
				@left_child.add_start(x, bits)
			else
				@right_child.add_start(x, bits)
			end
		end
	end

	def add_end(x, bits)
		if @range_min == @range_max
			@end |= bits
		else
			if x <= @left_child.range_max
				@left_child.add_end(x, bits)
			else
				@right_child.add_end(x, bits)
			end
		end
	end

	def add_between(x, y, bits)
		return if x > y

		if x == @range_min && y == @range_max
			@between |= bits
		else
			lr = @left_child.range_max
			@left_child.add_between(x, lr < y ? lr : y, bits)
			rl = @right_child.range_min
			@right_child.add_between(rl > x ? rl : x, y, bits)
		end
	end

	def force
		if @range_min != @range_max
			@left_child.take(@start, @between, @end)
			@right_child.take(@start, @between, @end)
		end
		@star = @between = @end = 0
	end

	def take(start, between, finish)
		@start |= start
		@between |= between
		@end |= finish
	end

	def net_start_count(x)
		if @range_min == @range_max
			bits = @start
			bits -= bits & @end
			bits -= bits & @between
			bits.to_s(2).count("1")
		else
			force
			if x <= @left_child.range_max
				@left_child.net_start_count(x)
			else
				@right_child.net_start_count(x)
			end
		end
	end

	def net_end_count(x)
		if @range_min == @range_max
			bits = @end
			bits -= bits & @start
			bits -= bits & @between
			bits.to_s(2).count("1")
		else force
			if x <= @left_child.range_max
				@left_child.net_end_count(x)
			else
				@right_child.net_end_count(x)
			end
		end
	end
end


ones = [0]
10000.times{
	ones << ((ones[-1] << 1) | 1)
}

t = Time.new

loop {
	n, r = gets.split.map(&:to_i)
	break if n == 0


	a = (1..n).map{ gets.split.map(&:to_i) }
	max_x = a.map{|_,_,x2,_| x2}.max
	max_y = a.map{|_,_,_,y2| y2}.max
	v_st = LazySegmentTree.new(max_x+1)
	h_st = LazySegmentTree.new(max_y+1)

	a.each {|x1, y1, x2, y2|
		bits = ones[y2-y1] << y1
		v_st.add_start(x1, bits)
		v_st.add_between(x1+1, x2-1, bits) if x1+1 < x2
		v_st.add_end(x2, bits)
		bits = ones[x2-x1] << x1
		h_st.add_start(y1, bits)
		h_st.add_between(y1+1, y2-1, bits) if y1+1 < y2
		h_st.add_end(y2, bits)
	}

	area = 0
	for x in 0..max_x
		area += v_st.net_start_count(x) * (10000-x)
		area -= v_st.net_end_count(x) * (10000-x)
	end
	p area

	if r == 2
		len = 0
		for x in 0..max_x
			len += v_st.net_start_count(x)
			len += v_st.net_end_count(x)
		end
		for y in 0..max_y
			len += h_st.net_start_count(y)
			len += h_st.net_end_count(y)
		end
		p len
	end
}