「SOL」Quick Tortoise (Codeforces)
阿新 • • 發佈:2021-06-17
只能說沒想到
題面
給出一個 \(n\times m\) 的網格圖,每個格子要麼是空地要麼是障礙。
給出 \(q\) 個詢問,每次給出 \((sx, sy),(ex,ey)\),問從 \((sx,sy)\) 出發,只能向下或向右走,能否到達 \((ex,ey)\)。
資料規模:\(n,m\le500\),\(q\le6\times10^5\)。
解析
只能向右或向下走就保證了轉移無環,由此聯想到另一道題(忘了具體哪道題了):用線段樹維護從 \((l,i)\) 到 \((r,j)\) 的路徑資訊。該題主要利用了兩條路徑比較容易合併的性質。
這道題不涉及修改,不需要線段樹,可以直接貓樹分治。
將詢問離線,每次處理橫座標跨過區間中點的詢問。對區間 \([l,r]\)
詢問只需要判斷是否存在 \(k\) 使得路徑 \((sx,sy)\to(mid,k)\to(ex,ey)\) 合法。
可以用 bitset
優化 —— 儲存 \((p,i)\) 向右下走能到達 \(x=mid\) 的哪些點,以及 \((q,j)\) 向左上走能到達 \(x=mid\) 的哪些點。查詢可以一次 bitset
求交集。
複雜度 \(\mathcal{O}(\frac{n^3\log n+nq}{w})\)
原始碼
/* Lucky_Glass */ #include <bitset> #include <cstdio> #include <cassert> #include <cstring> #include <algorithm> #define CON(typ) const typ & const int N = 505, M = 6e5 + 10; int rin(int &r) { int c = getchar(); r = 0; while (c < '0' || '9' < c) c = getchar(); while ('0' <= c && c <= '9') r = r * 10 + (c ^ '0'), c = getchar(); return r; } int n, m, qry_cnt; char maz[N][N]; int qry[M][4], qry_id[M], tmp_id[M]; bool ans[M]; std::bitset<N> dp[N][N], dp_rev[N][N]; void solve(CON(int) xl, CON(int) xr, CON(int) ql, CON(int) qr) { if (ql > qr) return; assert(xl <= xr); int mi = (xl + xr) >> 1; for (int j = m; j; --j) if (maz[mi][j] == '.') dp[mi][j] = dp[mi][j + 1], dp[mi][j].set(j, 1); else dp[mi][j] = 0; for (int i = mi - 1; i >= xl; --i) for (int j = m; j; --j) if (maz[i][j] == '.') dp[i][j] = dp[i + 1][j] | dp[i][j + 1]; else dp[i][j] = 0; for (int j = 1; j <= m; ++j) if (maz[mi][j] == '.') { dp_rev[mi][j] = dp_rev[mi][j - 1], dp_rev[mi][j].set(j, 1); } else { dp_rev[mi][j] = 0; } for (int i = mi + 1; i <= xr; ++i) for (int j = 1; j <= m; ++j) if (maz[i][j] == '.') dp_rev[i][j] = dp_rev[i - 1][j] | dp_rev[i][j - 1]; else dp_rev[i][j] = 0; int qll = ql - 1, qrr = qr + 1; for (int i = ql; i <= qr; ++i) if (qry[qry_id[i]][0] <= mi && mi <= qry[qry_id[i]][2]) { int *now = qry[qry_id[i]]; ans[qry_id[i]] = (dp[now[0]][now[1]] & dp_rev[now[2]][now[3]]) != 0; } else if (qry[qry_id[i]][0] > mi) { tmp_id[--qrr] = qry_id[i]; } else { tmp_id[++qll] = qry_id[i]; } for (int i = ql; i <= qll; ++i) qry_id[i] = tmp_id[i]; for (int i = qrr; i <= qr; ++i) qry_id[i] = tmp_id[i]; solve(xl, mi - 1, ql, qll); solve(mi + 1, xr, qrr, qr); } int main() { rin(n), rin(m); for (int i = 1; i <= n; ++i) scanf("%s", maz[i] + 1); rin(qry_cnt); for (int i = 1; i <= qry_cnt; ++i) { rin(qry[i][0]), rin(qry[i][1]), rin(qry[i][2]), rin(qry[i][3]); qry_id[i] = i; } solve(1, n, 1, qry_cnt); for (int i = 1; i <= qry_cnt; ++i) printf("%s\n", ans[i] ? "Yes" : "No"); return 0; }
THE END
Thanks for reading!
歷過滄海的變遷
再難為江河的渦旋
我尋找著 沉默的桑田 坎坷萬千
眺望過巫山之巔
再不是浮雲的翩躚
我尋找著 屬於我的那片雲煙
在下個時刻出現
——《巫山雲》By Snapmod / 詩岸
Link 巫山雲 - 網易雲