Problem:
Lucky Dip

Time Limit: 8 sec / Memory Limit: 64 MB

C: 福袋

福袋，それは年始を祝う商習慣の一つである．
人気の福袋には多くの人が開店前から行列を作り，ターゲットの福袋へダッシュする．
この風物詩に魅了されたあなたは，今年もお目当ての福袋を狙い，計画を立てていた．

しかし，お客を呼び寄せる側の某百貨店の店長は頭を悩ませていた．
どうやらフロアの準備が開店に間に合いそうにない．

そこで店長はある一つのアイディアを思いついた．
それは開店後，店内を徐々に開放すればなんとか営業できるのではないかというものである．

あなたは刻一刻と変化する店内の情報を元に，お目当ての福袋がどの時間帯から入手できるのかを調べたい．

Input

入力は単一のデータセットで与えられ，EOFで終了する．

店内の様子は各行が W 文字からなる H 行の文字列で表される．

1 行目

W H
2 < W, H <= 1000

続く H 行

店内の様子

.: 床

#: 壁

t: 目的の福袋

目的の福袋は店内に必ず1つだけ存在する．

H + 2 行目

営業時間 N (0 <= N <= 1000)

続く N 行

x1 y1
x2 x2
...
xi yi
...
xn yn

(xi, yi)は，i 時間目に開放される壁の座標を表す．(0 <= xi < W, 0 <= yi < H)

xi が列，yi が行である．

開放される壁の座標の位置が "#" なら "." に置き換え，"." なら何もしない．

目的の福袋が開放されることはない．

(0, 0) が壁になることはない．

またあるマスからの移動は，上下左右の4方向のマスへのみが可能であり，壁の上へ移動することはできないものとする．

Output

左上(0, 0) から t の座標へ辿りつけるようになる時間 s (-1 <= s <= N)を1行で出力せよ．

壁を開放せずに辿りつける場合，0 を出力せよ．

営業時間が終了しても到達できなければ -1 を出力すること．

Sample Input 1

10 10
.....#....
.....#....
.....#....
######....
..........
####......
....###...
t..#..####
...##.....
....#...##
3
0 3
0 5
4 6

Sample Output 1

2

Sample Input 2

10 10
.....#....
.....#....
.....#....
##########
##########
##########
##########
t..#..####
...##.....
....#...##
3
0 3
0 5
4 6

Sample Output 2

-1

Solution in C++ (judge verdict: Accepted)

#include <iostream>
#include <string>
#define N1 (1000+1)
using namespace std;
int find(int);
void unite(int,int);
bool same(int,int);
int tree[N1*N1];
string str[N1];
int main(){
  int W,H,N,x,y,findy,findx;
  int dx[4]={0,1,0,-1};
  int dy[4]={-1,0,1,0};
  cin >> W >> H;
  for(int i=0;i<H;i++) cin >> str[i];
  for(int i=0;i<H;i++){
    for(int j=0;j<W;j++){
      tree[i*W+j]=i*W+j;      
    }
  }
  for(int i=0;i<H;i++){
    for(int j=0;j<W;j++){
      if(str[i][j]=='t') findy=i,findx=j;
      if(str[i][j]!='#'){
	for(int k=0;k<4;k++)
	  if(0<=i+dy[k]&&i+dy[k]<H&&0<=j+dx[k]&&j+dx[k]<W)
	    if(str[i+dy[k]][j+dx[k]]!='#')
	      unite(i*W+j,(i+dy[k])*W+(j+dx[k]));
      }
    }
  }
  cin >> N;
  int flag=0;
  if(same(0,findy*W+findx)){
    flag=1;
    cout << 0 << endl;
  }
  int cnt=0;
  while(N--&&flag==0){
    cnt++;
    cin >> x >> y;
    str[y][x]='.';
    for(int i=0;i<4;i++)
      if(0<=y+dy[i]&&y+dy[i]<H&&0<=x+dx[i]&&x+dx[i]<W&&str[y+dy[i]][x+dx[i]]!='#')
	unite(y*W+x,(y+dy[i])*W+(x+dx[i]));
    if(same(0,findy*W+findx)){
      flag=1;
      cout << cnt << endl;
      break;
    }
  }
  if(flag==0) cout << -1 << endl;
  return 0;
}
int st[N1*N1];
int find(int x){
  int cnt=0;
  while(x!=tree[x]){
    x=tree[x];
    st[cnt]=x;
    cnt++;
  }
  while(cnt>0){
    cnt--;
    tree[st[cnt]]=x;
  }
  return x;
}
void unite(int x,int y){
  x=find(x),y=find(y);
  if(x==y) return ;
  if(x<y) swap(x,y);
  tree[x]=y;
}
bool same(int x,int y){
  if(find(x)==find(y)) return true;
  return false;
}