TIOJ 1749:[APIO '11] Path
TIOJ 1749:[APIO '11] Path
題目大意:平面上有兩個點 $(sx,sy),(ex,ey)$ 和 $n$ 個邊與座標軸平行的矩形,矩形皆不相交,只能在矩形上轉彎,問從 $(sx,sy)$ 走到 $(ex, ey)$ 的最短距離,或是不可能。
解法:我的第一種作法是把所有 $x,y$ 座標離散化,然後對這 $O(n^2)$ 個點建邊,結果 $\texttt{MLE}$ 了,然後我把距離的 $\texttt{long long}$ 改用一個 $\texttt{int}$ 跟 $\texttt{short}$ 存,空間壓過了,可是 $\texttt{TLE}$ 了。之後觀察到每次走的邊其中一個端點一定是起終點或矩形頂點,所以可以只對這些點建邊,寫了很久才過。
$\text{Code:}$
#pragma GCC optimize("O3,unroll-loops")
#pragma GCC target("avx,popcnt,sse4,abm")
#include <bits/stdc++.h>
using namespace std;
#ifdef WAIMAI
#define debug(HEHE...) cout << "[" << #HEHE << "] : ", dout(HEHE)
void dout() {cout << '\n';}
template<typename T, typename...U>
void dout(T t, U...u) {cout << t << (sizeof...(u) ? ", " : ""), dout(u...);}
#else
#define debug(...) 7122
#endif
#define ll long long
#define Waimai ios::sync_with_stdio(false), cin.tie(0)
#define FOR(x,a,b) for (int x = a, I = b; x <= I; x++)
#define pb emplace_back
#define F first
#define S second
const ll INF = 1e18;
const int SIZE = 1005;
const int mask = (1 << 10) - 1;
struct LIS {
vector<int> lis;
void init() {
lis.clear();
}
void add(int x) {
lis.pb(x);
}
void work() {
sort(lis.begin(), lis.end());
lis.erase(unique(lis.begin(), lis.end()), lis.end());
}
int id(int x) {
return lower_bound(lis.begin(), lis.end(), x) - lis.begin() + 1;
}
int operator [] (const int& x) const {
return lis[x - 1];
}
} lisx, lisy;
int n, szx, szy;
int sx, sy, ex, ey;
pair<int, int> x[SIZE], y[SIZE];
vector<pair<int, short>> vx[2 * SIZE], vy[2 * SIZE];
int sz;
unordered_set<int> us;
unordered_map<int, int> mp;
vector<vector<pair<int, int>>> adj;
vector<ll> dis;
inline int id(int x, int y) {
return (x - 1) * szy + y - 1;
}
inline int mid(int x, int y) {
if (!mp.count(id(x, y))) mp[id(x, y)] = sz++;
return mp[id(x, y)];
}
void solve() {
cin >> sx >> sy >> ex >> ey;
cin >> n;
FOR (i, 1, n) {
cin >> x[i].F >> y[i].F >> x[i].S >> y[i].S;
if (x[i].F > x[i].S) swap(x[i].F, x[i].S);
if (y[i].F > y[i].S) swap(y[i].F, y[i].S);
}
lisx.init(), lisx.add(sx), lisx.add(ex);
lisy.init(), lisy.add(sy), lisy.add(ey);
FOR (i, 1, n) {
lisx.add(x[i].F), lisx.add(x[i].S);
lisy.add(y[i].F), lisy.add(y[i].S);
}
lisx.work(), sx = lisx.id(sx), ex = lisx.id(ex);
lisy.work(), sy = lisy.id(sy), ey = lisy.id(ey);
FOR (i, 1, n) {
x[i].F = lisx.id(x[i].F), x[i].S = lisx.id(x[i].S);
y[i].F = lisy.id(y[i].F), y[i].S = lisy.id(y[i].S);
}
szx = lisx.lis.size(), szy = lisy.lis.size();
FOR (x, 1, szx) vx[x].clear();
FOR (y, 1, szy) vy[y].clear();
int stx = 1, sty = 1, etx = 1, ety = 1, sid = 0, eid = n + 1;
auto add = [&](int i, int x, int y, int tx, int ty, int is = 0) {
if (!is && x == sx && y == sy) {
sid = i;
stx |= tx, sty |= ty;
return;
}
if (!is && x == ex && y == ey) {
eid = i;
etx |= tx, ety |= ty;
return;
}
vx[x].pb(y, tx << 10 | i);
vy[y].pb(x, ty << 10 | i);
};
FOR (i, 1, n) {
for (int cx : {x[i].F, x[i].S}) for (int cy : {y[i].F, y[i].S}) add(i, cx, cy, 1, 1);
FOR (j, x[i].F + 1, x[i].S - 1) {
add(i, j, y[i].F, 2, 0);
add(i, j, y[i].S, 0, 0);
}
FOR (j, y[i].F + 1, y[i].S - 1) {
add(i, x[i].F, j, 0, 2);
add(i, x[i].S, j, 0, 0);
}
}
add(sid, sx, sy, stx, sty, 1);
add(eid, ex, ey, etx, ety, 1);
sz = 0, us.clear(), mp.clear(), adj.clear(), dis.clear();
FOR (x, 1, szx) {
sort(vx[x].begin(), vx[x].end());
for (int i = 0; i < vx[x].size(); i++) if (vx[x][i].S >> 10 & 1) {
us.insert(id(x, vx[x][i].F));
if (i > 0 && ((vx[x][i - 1].S >> 10 & 1) || (vx[x][i - 1].S & mask) != (vx[x][i].S & mask))) us.insert(id(x, vx[x][i - 1].F));
if (i + 1 < vx[x].size() && !(vx[x][i].S >> 10 & 2) && ((vx[x][i + 1].S >> 10 & 1) || (vx[x][i + 1].S & mask) != (vx[x][i].S & mask))) us.insert(id(x, vx[x][i + 1].F));
}
}
FOR (y, 1, szy) {
sort(vy[y].begin(), vy[y].end());
for (int i = 0; i < vy[y].size(); i++) if (vy[y][i].S >> 10 & 1) {
us.insert(id(vy[y][i].F, y));
if (i > 0 && ((vy[y][i - 1].S >> 10 & 1) || (vy[y][i - 1].S & mask) != (vy[y][i].S & mask))) us.insert(id(vy[y][i - 1].F, y));
if (i + 1 < vy[y].size() && !(vy[y][i].S >> 10 & 2) && ((vy[y][i + 1].S >> 10 & 1) || (vy[y][i + 1].S & mask) != (vy[y][i].S & mask))) us.insert(id(vy[y][i + 1].F, y));
}
}
adj.resize(us.size()), dis.resize(us.size(), INF);
FOR (x, 1, szx) {
int ly = -1, lt;
for (int i = 0; i < vx[x].size(); i++) if (us.count(id(x, vx[x][i].F))) {
auto [y, t] = vx[x][i];
if (ly != -1 && !(lt & 2)) {
adj[mid(x, ly)].pb(mid(x, y), lisy[y] - lisy[ly]);
adj[mid(x, y)].pb(mid(x, ly), lisy[y] - lisy[ly]);
}
ly = y, lt = t >> 10;
}
}
FOR (y, 1, szy) {
int lx = -1, lt;
for (int i = 0; i < vy[y].size(); i++) if (us.count(id(vy[y][i].F, y))) {
auto [x, t] = vy[y][i];
if (lx != -1 && !(lt & 2)) {
adj[mid(lx, y)].pb(mid(x, y), lisx[x] - lisx[lx]);
adj[mid(x, y)].pb(mid(lx, y), lisx[x] - lisx[lx]);
}
lx = x, lt = t >> 10;
}
}
priority_queue<pair<ll, int>, vector<pair<ll, int>>, greater<pair<ll, int>>> pq;
pq.emplace(dis[mid(sx, sy)] = 0, mid(sx, sy));
while (pq.size()) {
auto [d, pos] = pq.top();
pq.pop();
if (d > dis[pos]) continue;
if (pos == mid(ex, ey)) {
cout << d << '\n';
return;
}
for (auto [np, w] : adj[pos]) if (d + w < dis[np]) pq.emplace(dis[np] = d + w, np);
}
cout << "No Path\n";
}
int main() {
Waimai;
int tt;
cin >> tt;
while (tt--) solve();
}
我的分享就到這裡結束了,如果喜歡我的 $\text{Blog}$,歡迎追蹤!
留言
張貼留言