Problem:
Problem F: Cosmic Market

Cosmic market(コズミック・マーケット)、通称コズミケ、は全宇宙最大規模の同人即売会だ。
コズミケにはあらゆるジャンルの同人愛好家達が集う。
近年、コズミケへの来場者は増加傾向にある。
最初から全ての人が入場できると大変混雑して危険なので、開場直後は入場規制を行っている。
ある一定人数の人だけが開場と同時に入場することが出来るのだ。
それ以外の人たちはしばらく待ってからの入場となっている。

しかし先着順に会場に入ることにすると、徹夜で前日から並ぶ人が出てしまう。
コズミケの参加者には未成年も多く、治安上の問題もあるので先着順という決め方はとても良くない。
そういう理由があって、コズミケでは参加者の中である種のゲームを行い、そのゲームで勝ち残った人が最初に入場する権利を手にできる。
公平を期すために毎年ランダム性の高いゲームを採用している。

僕は今回もコズミケに参加する予定だ。
僕は今回のコズミケでどうしても手に入れたい同人誌がある。
とある人気サークルが頒布する同人誌で、今年の春に話題になった魔法少女のアニメを取り扱っている。
しかし、このサークルはとても人気で毎回すぐに頒布が終了してしまう。
開場と同時に入場できなかった場合に手に入れることはほぼ不可能だろう。
もちろん後日同人ショップなどでも手に入るようになるのは間違いない。しかしそれまで我慢することなど僕には出来ない。
僕はどんな手を使ってでもコズミケ当日に手に入れなくてはいけないのだ。
不幸なことに僕は今までのコズミケで最初に入場できたことは一度もない。

コズミケのカタログによると、今回は以下のようなゲームで最初に入場できる人を選ぶらしい。
まず参加者のうち先着 r×c 人の人が、r×c　のグリッドのように配置された座席の好きな場所に座る。
先着順で場所を選べるので早く行った方が選択肢が沢山ある。
r×c 人の人が座ったらゲームが始まる。
このゲームはある一定の回数、ある1つの列（行）の座席にいる全ての人に対して、着席、あるいは起立が指示される。
すでに着席している人に着席の指示が出された場合はそのまま待機すれば。起立している人も同様である。
この指示が出される対象の列（行）と指示の内容はランダムにルーレットで決められる。
ある一定の回数の指示が終わった時点で起立している人だけが最初に開場に入れるのだ。
指示の回数は参加者には知らされていないので、いつゲームが終わるか分からない。
なのである時点で立っている人も座っている人も自分が最初に入場できるかは分からない。
だからスリルを味わうことが出来る、とカタログでは強調されている。

コズミケ前日の午後1時、僕は今年のゲームに関するデータをすべて手に入れた。
僕が手に入れた情報によると、この指示の回数、q はすでに決まっている。
それどころかq 回の指示内容が全てがすでに決まっている。
ランダム性が高いなどといわれているがそれは嘘だったのだ。
どういう理由があって事前に決まっているのかは分からない。
しかしこの情報は僕にとっては天の恵みのようだ。

もしこのデータどおりにゲームが行われれるのであれば、最初に入場することが出来る座席の場所が全て分かる。
最悪の場合、僕以外の参加者全員がこの情報を得ていたとしてみよう。
そんな場合でも遅くとも何番目に開場に到着すれば最初に会場に入ることが出来るかわかるはずだ。
しかしこの指示内容を今から手計算で解析するのは量が多すぎるので無理そうだ。
どんなに頑張ってもコズミケには間に合わない。

そこで、僕は君にこの計算を任せることにした。
君はプログラミングコンテストによく参加しており、このようなの計算プログラムを書くのは得意なはずだ。
もちろんただでやってくれとは言わない。
カタログによると、今年のコズミケにはプログラミングコンテストに関する同人誌を出しているサークルが参加する予定のはずだ。
もし僕が開場と同時に入場できたら報酬としてその同人誌を手に入れて君にプレゼントするよ。
さて、僕はこれから5時間ぐらい仮眠をとることにしよう。その間に君ならきっと答えを出してくれると僕は信じている。

Input

入力は複数のケースからなる。
各ケースは以下のフォーマットで与えられる。

r c q
A0 B0 order0
A1 B1 order1
.
.
.
Aq-1 Bq-1 orderq-1

Ai = 0 の時,Bi 行目に対してorderi の指示が実行される。

Ai = 1 の時,Bi 列目に対してorderi の指示が実行される。

orderi = 0の時は指定された行または列の人全員を座らせる。

orderi = 1の時は指定された行または列を人全員を立たせる。

入力の終わりはr =0 c =0 q =0 で与えられる。

入力の値は以下の条件を満たす。

1 ≤ r ≤ 50,000

1 ≤ c ≤ 50,000

1 ≤ q ≤ 50,000

orderi = 0 または 1

Ai = 0 の時

0 ≤ Bi < r

Ai = 1 の時

0 ≤ Bi < c

テストケースの数は100を超えない

Output

最悪の場合に、何番目までに到着すれば最初に会場に入れる権利を得ることが出来るかを一行で出力せよ。

Sample input

5 5 5
0 0 1
0 0 0
0 2 0
1 2 1
0 0 0
5 5 5
1 4 0
0 1 1
0 4 1
1 3 0
0 3 1
5 5 5
1 0 0
0 3 0
1 2 1
0 4 0
0 1 1
0 0 0

Sample output

4
13
8

The University of Aizu Programming Contest 2011 Summer

原案、問題文: Tomoya Sakai

Solution in C (judge verdict: Time Limit Exceeded)

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

#define SEGTREE_MAX 65536

#define INTERNAL_SEGTREE_MAX (SEGTREE_MAX*2-1)

typedef struct {
	short stand;
	short sit;
} segtree_t;

segtree_t segtree[INTERNAL_SEGTREE_MAX];

void segtree_init(void) {
	memset(segtree,0,sizeof(segtree));
}

/* internal */
void segtree_update(int youso) {
	int min;
	min=0x7fff;
	if(segtree[youso*2+1].stand<min)min=segtree[youso*2+1].stand;
	if(segtree[youso*2+2].stand<min)min=segtree[youso*2+2].stand;
	segtree[youso].stand=min;

	min=0x7fff;
	if(segtree[youso*2+1].sit<min)min=segtree[youso*2+1].sit;
	if(segtree[youso*2+2].sit<min)min=segtree[youso*2+2].sit;
	segtree[youso].sit=min;

	if(youso>0)segtree_update((youso-1)/2);
}

/* internal */
int segtree_getnum_internal(
		int youso,int target,int start,int end,int isstand,
		int kstart,int kend) {
	if(youso>=INTERNAL_SEGTREE_MAX)return 0;
	if(end<=kstart || kend<=start)return 0;
	else if(start<=kstart && kend<=end) {
		if((isstand?segtree[youso].stand:segtree[youso].sit)>target) {
			return kend-kstart;
		} else {
			return
				segtree_getnum_internal(youso*2+1,
					target,start,end,isstand,
					kstart,kstart+(kend-kstart)/2)+
				segtree_getnum_internal(youso*2+2,
					target,start,end,isstand,
					kstart+(kend-kstart)/2,kend);
		}
	} else {
		return
			segtree_getnum_internal(youso*2+1,
				target,start,end,isstand,
				kstart,kstart+(kend-kstart)/2)+
			segtree_getnum_internal(youso*2+2,
				target,start,end,isstand,
				kstart+(kend-kstart)/2,kend);
	}
}

void segtree_set(int youso,int zikan,int isstand) {
	int youso2=youso+SEGTREE_MAX-1;
	if(isstand) {
		segtree[youso2].stand=zikan;
		segtree[youso2].sit=0;
	} else {
		segtree[youso2].sit=zikan;
		segtree[youso2].stand=0;
	}
	segtree_update((youso2-1)/2);
}

/* [start,end)ツづargetツづヲツづィツ妥・ツつォツつ「ツ要ツ素ツづ個青板づーツ仰づ淞づゥ */
int segtree_getnum(int target,int start,int end,int isstand) {
	return segtree_getnum_internal(0,target,start,end,isstand,
		0,SEGTREE_MAX);
}

int width,height;
segtree_t gyou_data[50000];

int main(void) {
	int query_num,i;
	int q_isretu,q_id,q_order;
	int result;
	while(1) {
		scanf("%d%d%d",&height,&width,&query_num);
		if(height==0 && width==0 && query_num==0)break;
		segtree_init();
		memset(gyou_data,0,sizeof(gyou_data));
		for(i=1;i<=query_num;i++) {
			scanf("%d%d%d",&q_isretu,&q_id,&q_order);
			if(q_isretu) {
				segtree_set(q_id,i,q_order);
			} else {
				if(q_order)gyou_data[q_id].stand=i;
				else gyou_data[q_id].sit=i;
			}
		}
		result=0;
		for(i=0;i<height;i++) {
			if(gyou_data[i].stand>gyou_data[i].sit) {
				result+=width-segtree_getnum(gyou_data[i].stand,
					0,width,0);
			} else {
				result+=segtree_getnum(gyou_data[i].sit,
					0,width,1);
			}
		}
		printf("%d\n",result);
	}
	return 0;
}