1068 - School of Killifish

http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=1068&lang=jp

問題

解法

二次元RMQ。
SegmentTreeを入れ子にする。
蟻本を参考にして実装した。
自分はいつもINFを1<<29とかにしているが、今回それだとまずい。
それにしても引数の数・・・。

ソース

const int INF = INT_MAX;

vector<vector<int> > dat;
int R, C;

void update(int r, int c, int a) {
  bool f = 0;
  if (r==0&&c==1) f = 1;
  r += R - 1;
  c += C - 1;
  dat[r][c] = a;
  int cc = c;
  while(cc > 0) {
    cc = (cc-1) / 2;
    dat[r][cc] = min(dat[r][cc*2+1], dat[r][cc*2+2]);
  }
  while(r > 0) {
    r = (r-1) / 2;
    cc = c;
    while(1) {
      dat[r][cc] = min(dat[r*2+1][cc], dat[r*2+2][cc]);
      if (cc == 0) break;
      cc = (cc-1) / 2;
    }
  }
}

int query(int r1, int c1, int r2, int c2, int r, int rl, int rr, int c, int cl, int cr) {
  if (rr<=r1 || r2<=rl || cr<=c1 || c2<=cl) return INF;
  if (r1 <= rl && rr <= r2 && c1 <= cl && cr <= c2) return dat[r][c];
  if (r1 <= rl && rr <= r2) {   // 縦を分割
    int v1 = query(r1,c1,r2,c2,r,rl,rr,c*2+1,cl,(cl+cr)/2);
    int v2 = query(r1,c1,r2,c2,r,rl,rr,c*2+2,(cl+cr)/2, cr);
    return min(v1,v2);
  } else {                      // 横を分割
    int v1 = query(r1,c1,r2,c2,r*2+1,rl,(rl+rr)/2,c,cl,cr);
    int v2 = query(r1,c1,r2,c2,r*2+2,(rl+rr)/2,rr,c,cl,cr);
    return min(v1,v2);
  }
}
int main() {
  int q;
  while(cin >>R>>C>>q, R||C||q) {
    int RR = R, CC = C;
    R = 1; C = 1;
    while(R < RR) R *= 2;
    while(C < CC) C *= 2;
    dat.assign(2*R-1, vector<int>(2*C-1, INF));
    REP(i,RR) REP(j,CC) {
      int a;
      cin >> a;
      update(i,j,a);
    }
    REP(i,q) {
      int r1,c1,r2,c2;
      cin >> r1 >> c1 >> r2 >> c2;
      cout << query(r1,c1,r2+1,c2+1,0,0,R,0,0,C) << endl;
    }
    
  }
}