Untitled
unknown
plain_text
a year ago
15 kB
3
Indexable
Never
#include <iostream> #include <vector> #include <queue> #include <set> using namespace std; typedef long long ll; typedef pair<ll, ll> pll; typedef pair<ll, pll> plll; const bool DEBUG = true; const ll T_ZONE = 0, I_ZONE = 1, NO_ZONE = 2, NE_ZONE = 3, SE_ZONE = 4, SO_ZONE = 5, OUT_ZONE = 6; void rotate_clockwise(ll& x, ll& y){ ll aux = x; x = y; y = -aux; } void rotate_counterclockwise(ll& x, ll& y){ ll aux = x; x = -y; y = aux; } ll getZone(ll siz, ll x, ll y){ if (abs(x) >= siz || abs(y) >= siz) return OUT_ZONE; if (x == 0 && y > 0) return I_ZONE; if (y == 0) return T_ZONE; if (x == 0) return T_ZONE; if (x < 0 && y < 0) return SO_ZONE; if (x < 0 && y > 0) return NO_ZONE; if (x > 0 && y > 0) return NE_ZONE; return SE_ZONE; } ll getZone(ll siz, pll a){ return getZone(siz, a.first,a.second); } ll manhattan(ll x, ll y, ll xx, ll yy){ return abs(xx - x) + abs(yy-y); } ll getExteriorDist(ll siz, ll x, ll y, ll xx, ll yy){ if (abs(x) < siz && abs(xx) < siz){ if ((y >= siz && yy <= -siz) || (y <= -siz && yy >= siz)){ return abs(yy - y) + min(siz - x + siz - xx, siz + x + siz + xx); } } if (abs(y) < siz && abs(yy) < siz){ if ((x >= siz && xx <= -siz) || (x <= -siz && xx >= siz)){ return abs(xx - x) + min(siz - y + siz - yy, siz + y + siz + yy); } } return manhattan(x,y,xx,yy); } ll getTDist(ll siz, ll x, ll y){ return abs(x) + abs(siz + y); } plll getTotalExit(ll N, ll x, ll y){ ll siz = (1LL << N)/2; ll z = getZone(siz,x,y); if (z == T_ZONE){ return plll(getTDist(siz,x,y), pll(0, -siz)); } if (z == I_ZONE){ return plll(siz - y, pll(0, siz)); } if (z == OUT_ZONE){ return plll(0, pll(x, y)); } if (z == NE_ZONE || z == NO_ZONE){ y-= siz/2; } if (z == SE_ZONE || z == SO_ZONE){ y+= siz/2; } if (z == NO_ZONE || z == SO_ZONE){ x += siz/2; } if (z == NE_ZONE || z == SE_ZONE){ x -= siz/2; } if (z == SO_ZONE){ rotate_counterclockwise(x,y); } if (z == SE_ZONE){ rotate_clockwise(x,y); } plll e = getTotalExit(N-1, x, y); pll ePos = e.second; if (z == SO_ZONE){ rotate_clockwise(e.second.first, e.second.second); } if (z == SE_ZONE){ rotate_counterclockwise(e.second.first, e.second.second); } if (z == NE_ZONE || z == NO_ZONE){ e.second.second+= siz/2; } if (z == SE_ZONE || z == SO_ZONE){ e.second.second-= siz/2; } if (z == NO_ZONE || z == SO_ZONE){ e.second.first -= siz/2; } if (z == NE_ZONE || z == SE_ZONE){ e.second.first += siz/2; } ll newZ = getZone(siz, e.second); if (newZ == OUT_ZONE) return e; if (newZ == T_ZONE){ return plll(e.first + getTDist(siz,e.second.first,e.second.second), pll(0, -siz)); } if (newZ == I_ZONE){ return plll(e.first + siz - e.second.second, pll(0, siz)); } if (DEBUG) cerr << "GIGA FAIL" << endl; return plll(-1, pll(0,0)); } plll getExit(ll N, ll x, ll y){ ll siz = (1LL << N)/2; ll z = getZone(siz,x,y); if (DEBUG) cerr << "CHECKING TOTAL EXIT " << N << " " << x << " " << y << " " << z << endl; if (z == T_ZONE || z == I_ZONE || z == OUT_ZONE){ return plll(0, pll(x,y)); } if (z == NE_ZONE || z == NO_ZONE){ y-= siz/2; } if (z == SE_ZONE || z == SO_ZONE){ y+= siz/2; } if (z == NO_ZONE || z == SO_ZONE){ x += siz/2; } if (z == NE_ZONE || z == SE_ZONE){ x -= siz/2; } if (z == SO_ZONE){ rotate_counterclockwise(x,y); } if (z == SE_ZONE){ rotate_clockwise(x,y); } plll e = getTotalExit(N-1, x, y); if (DEBUG) cerr << "GOT ANSWER " << e.first << " " << e.second.first << " " << e.second.second << endl; pll ePos = e.second; if (z == SO_ZONE){ rotate_clockwise(e.second.first, e.second.second); } if (z == SE_ZONE){ rotate_counterclockwise(e.second.first, e.second.second); } if (z == NE_ZONE || z == NO_ZONE){ e.second.second+= siz/2; } if (z == SE_ZONE || z == SO_ZONE){ e.second.second-= siz/2; } if (z == NO_ZONE || z == SO_ZONE){ e.second.first -= siz/2; } if (z == NE_ZONE || z == SE_ZONE){ e.second.first += siz/2; } if (DEBUG) cerr << "GOT ANSWER TRANSFORMED " << e.first << " " << e.second.first << " " << e.second.second << endl; ll newZ = getZone(siz, e.second); if (newZ == T_ZONE || newZ == I_ZONE || newZ == OUT_ZONE) return e; if (DEBUG) cerr << "GIGA FAIL 2" << endl; return plll(-1, pll(0,0)); } ll findShortestPath(ll N, ll x,ll y, ll xx,ll yy){ ll siz = (1LL << N)/2; ll z1 = getZone(siz, x,y); ll z2 = getZone(siz, xx,yy); if (DEBUG) cerr << "ANALYZING SHORTEST PATH " << siz << " " << x << " " << y << " " << xx << " " << yy << endl; if (DEBUG) cerr << "ZONE 1 " << z1 << endl; if (DEBUG) cerr << "ZONE 2 " << z2 << endl; if (z1 > z2){ swap(z1, z2); swap(x,xx); swap(y,yy); } //CASE WHERE BOTH POINTS ARE NOT ON QUADRANTS if (z1 == T_ZONE && z2 == T_ZONE){ return manhattan(x,y,xx,yy); } if (z1 == T_ZONE && z2 == I_ZONE){ return getTDist(siz, x,y) + (siz-yy) + getExteriorDist(siz, 0, -siz, 0, siz); } if (z1 == T_ZONE && z2 == OUT_ZONE){ return getTDist(siz, x,y) + getExteriorDist(siz, 0, -siz, xx, yy); } if (z1 == I_ZONE && z2 == I_ZONE){ return manhattan(x,y,xx,yy); } if (z1 == I_ZONE && z2 == OUT_ZONE){ (siz-y) + getExteriorDist(siz, 0, siz, xx,yy); } if (z1 == OUT_ZONE && z2 == OUT_ZONE){ return getExteriorDist(siz, x,y, xx,yy); } if (N == 1) return 0; //ONE POINT ON QUADRANT, THE OTHER NOT if (z1 == T_ZONE){ plll e2 = getExit(N, xx,yy); if (getZone(siz, e2.second) == T_ZONE){ return e2.first + manhattan(e2.second.first, e2.second.second, x, y); } if (getZone(siz, e2.second) == I_ZONE){ return e2.first + getTDist(siz, x,y) + (siz - e2.second.second) + getExteriorDist(siz, 0, -siz, 0, siz); } return e2.first + getTDist(siz, x,y) + getExteriorDist(siz, 0, -siz, e2.second.first, e2.second.second); } if (z1 == I_ZONE){ plll e2 = getExit(N, xx,yy); if (getZone(siz, e2.second) == T_ZONE){ return e2.first + getTDist(siz, e2.second.first, e2.second.second) + (siz - y) + getExteriorDist(siz, 0, -siz, 0, siz); } if (getZone(siz, e2.second) == I_ZONE){ return e2.first + manhattan(e2.second.first, e2.second.second, x, y); } return e2.first + (siz - y) + getExteriorDist(siz, 0, siz, e2.second.first, e2.second.second); } if (z2 == OUT_ZONE){ plll e1 = getExit(N, x,y); if (getZone(siz, e1.second) == T_ZONE){ return e1.first + getTDist(siz, e1.second.first, e1.second.second) + getExteriorDist(siz, 0, -siz, xx, yy); } if (getZone(siz, e1.second) == I_ZONE){ return e1.first + (siz - e1.second.second) + getExteriorDist(siz, 0, siz, xx, yy); } return e1.first + getExteriorDist(siz, e1.second.first, e1.second.second, xx, yy); } //BOTH POINTS ON QUADRANTS plll e1 = getExit(N, x,y); plll e2 = getExit(N, xx,yy); ll ze1 = getZone(siz, e1.second); //these can only be T, I or OUT ll ze2 = getZone(siz, e2.second); //these can only be T, I or OUT if (ze2 < ze1){ swap(ze2, ze1); swap(e2, e1); swap(x,xx); swap(y,yy); swap(z1, z2); } if (DEBUG) cerr << "EXIT 1 " << e1.first << " " << e1.second.first << " " << e1.second.second << endl; if (DEBUG) cerr << "EXIT 2 " << e2.first << " " << e2.second.first << " " << e2.second.second << endl; //DIFF QUADS OR DIFF EXIT if (z1 != z2 || e1.second != e2.second){ if (ze1 == T_ZONE){ if (ze2 == T_ZONE){ return e1.first + e2.first + manhattan(e1.second.first, e1.second.second, e2.second.first, e2.second.second); } if (ze2 == I_ZONE){ return e1.first + e2.first + getTDist(siz, e1.second.first, e1.second.second) + (siz - e2.second.second) + getExteriorDist(siz, 0, -siz, 0, siz); } if (ze2 == OUT_ZONE){ return e1.first + e2.first + getTDist(siz, e1.second.first, e1.second.second) + getExteriorDist(siz, 0, -siz, e2.second.first, e2.second.second); } } if (ze1 == I_ZONE){ if (ze2 == I_ZONE){ return e1.first + e2.first + manhattan(e1.second.first, e1.second.second, e2.second.first, e2.second.second); } if (ze2 == OUT_ZONE){ return e1.first + e2.first + (siz - e1.second.second) + getExteriorDist(siz, 0, siz, e2.second.first, e2.second.second); } } if (ze1 == OUT_ZONE){ return e1.first + e2.first + getExteriorDist(siz, e1.second.first, e1.second.second, e2.second.first, e2.second.second); } } //SAME QUADS SAME EXIT if (z1 == NE_ZONE || z1 == NO_ZONE){ y-= siz/2; yy-= siz/2; } if (z1 == SE_ZONE || z1 == SO_ZONE){ y+= siz/2; yy+= siz/2; } if (z1 == NO_ZONE || z1 == SO_ZONE){ x += siz/2; xx += siz/2; } if (z1 == NE_ZONE || z1 == SE_ZONE){ x -= siz/2; xx -= siz/2; } if (z1 == SO_ZONE){ rotate_counterclockwise(x,y); rotate_counterclockwise(xx,yy); } if (z1 == SE_ZONE){ rotate_clockwise(x,y); rotate_clockwise(xx,yy); } return findShortestPath(N-1, x, y, xx, yy); } const int TEST_N = 4; void generateWalls(){ } typedef vector<ll> VLL; typedef vector<VLL> VVLL; typedef pair<pll, pll> ppll; typedef set<ppll> sppll; sppll unconnected; const vector<pll> dirs{pll(1, 0), pll(0,1), pll(-1, 0), pll(0, -1)}; const int EAST = 0; const int NORTH = 1; const int WEST = 2; const int SOUTH = 3; VVLL dists; bool canAccess(pll a, pll b){ if (b.first < -1 || b.first >= (1 << TEST_N)) return false; if (b.second < -1 || b.second >= (1 << TEST_N)) return false; return unconnected.find(ppll(a, b)) == unconnected.end(); } ll getShortestDist(ll x, ll y, ll xx, ll yy){ int length = (1 << TEST_N) + 1; dists = VVLL(length, VLL(length, 100000)); queue<pll> q; q.push(pll(x,y)); dists[x+1][y+1] = 0; while (!q.empty()){ pll f = q.front(); q.pop(); int df = dists[f.first+1][f.second+1]; if (f.first == xx && f.second == yy) return df; for (int i = 0; i < 4; ++i){ pll x = f; x.first += dirs[i].first; x.second += dirs[i].second; if (canAccess(f,x)){ int oldDist = dists[x.first+1][x.second+1]; if (oldDist > df + 1){ dists[x.first+1][x.second+1] = df+1; q.push(x); } } } } return -1; } struct vect{ pll pos; int dir; void advance(){ ll x = pos.first; ll y = pos.second; if (dir == NORTH){ //cerr << "inserting " << x-1 << " " << y << " " << pos.first << " " << pos.second << endl; unconnected.insert(ppll(pos, pll(x-1, y))); unconnected.insert(ppll(pll(x-1, y), pos)); } else if (dir == SOUTH){ //cerr << "inserting " << x-1 << " " << y-1 << " " << x << " " << y-1 << endl; unconnected.insert(ppll(pll(x-1, y-1), pll(x, y-1))); unconnected.insert(ppll(pll(x, y-1), pll(x-1, y-1))); } else if (dir == EAST){ //cerr << "inserting " << x << " " << y << " " << x << " " << y-1 << endl; unconnected.insert(ppll(pos, pll(x, y-1))); unconnected.insert(ppll(pll(x, y-1), pos)); } else { //cerr << "inserting " << x-1 << " " << y << " " << x-1 << " " << y-1 << endl; unconnected.insert(ppll(pll(x-1, y), pll(x-1, y-1))); unconnected.insert(ppll(pll(x-1, y-1), pll(x-1, y))); } pos.first += dirs[dir].first; pos.second += dirs[dir].second; } void rotateRight(){ dir = (dir + 3)%4; } void rotateLeft(){ dir = (dir + 1)%4; } }; vect v; void generateUnconnectedA (int n); void generateUnconnectedB(int n){ if (n == 0) return; v.rotateRight(); generateUnconnectedA(n-1); v.advance(); v.rotateLeft(); generateUnconnectedB(n-1); v.advance(); generateUnconnectedB(n-1); v.rotateLeft(); v.advance(); generateUnconnectedA(n-1); v.rotateRight(); } void generateUnconnectedA(int n){ if (n == 0) return; v.rotateLeft(); generateUnconnectedB(n-1); v.advance(); v.rotateRight(); generateUnconnectedA(n-1); v.advance(); generateUnconnectedA(n-1); v.rotateRight(); v.advance(); generateUnconnectedB(n-1); v.rotateLeft(); } void gUnc(){ v.pos = pll(0,0); v.dir = 0; generateUnconnectedA(TEST_N); } int main(){ ll k; cin >> k; for (ll i = 0; i < k; ++i){ ll n, x, y, xx, yy; cin >> n >> x >> y >> xx >> yy; ll siz = ((1LL << n)/2) - 1; x-= siz; y-= siz; xx -= siz; yy -= siz; cout << findShortestPath(n, x, y, xx, yy) << endl; } /*gUnc(); ll siz = ((1LL << TEST_N)/2) - 1; for (int i = -1; i < (1 << TEST_N) ; ++i){ for (int j = -1; j < (1 << TEST_N); ++j){ for (int ii = -1; ii < (1 << TEST_N); ++ii){ for (int jj = -1; jj < (1 << TEST_N) ; ++jj){ ll goodDist = getShortestDist(i,j,ii,jj); ll badDist = findShortestPath(TEST_N, i-siz, j-siz, ii-siz, jj-siz); if (goodDist != badDist){ cout << "DIFF " << i << " " << j << " " << ii << " " << jj << ": " << goodDist << " vs " << badDist << endl; } } } } }*/ }