제출 #1128398

#제출 시각아이디문제언어결과실행 시간메모리
1128398Zero_OP무지개나라 (APIO17_rainbow)C++20
0 / 100
116 ms72588 KiB
/* The planar graph : First, draw a "bound river" rectangle For example, the query : ("r" means river cell, "." means empty cell) ....rrrrr.. rrr....r... ..r....rrr. rrr.....r.. Draw a "bound river" rectangle => rrrrrrrrrrrrr r....rrrrr..r rrrr....r...r r..r....rrr.r rrrr.....r..r rrrrrrrrrrrrr - vertexes = number of r - edges = number of adjacent pairs r <-> r - *faces = our answer - connected components = if the whole river is "strictly" inside the rectangle => connected components = 2, otherwise cc = 1 - answer = *faces - *(number of block 2x2 of r) For example : rrrrrrrr r......r r..rr..r r......r rrrrrrrr so cc = 2 Euler Polyhedron Formula : V - E + F = 1 + C <=> answer = (F - 1) = E - V + C (excluded the outer face of the planar graph) */ #include "bits/stdc++.h" #ifndef LOCAL #include "rainbow.h" #endif using namespace std; #define rep(i, l, r) for(int i = (l); i < (r); ++i) #define sz(v) (int)v.size() #define dbg(x) "[" #x " = " << (x) << "]" #define all(v) begin(v), end(v) #define compact(v) v.erase(unique(all(v)), end(v)) #define file(name) if(fopen(name".inp", "r")){ freopen(name".inp", "r", stdin); freopen(name".out", "w", stdout); } template<typename T> bool minimize(T& a, const T& b){ if(a > b){ return a = b, true; } return false; } template<typename T> bool maximize(T& a, const T& b){ if(a < b){ return a = b, true; } return false; } mt19937 rng(chrono::steady_clock::now().time_since_epoch().count()); using ll = long long; using ld = long double; using ull = unsigned long long; using vi = vector<int>; using vl = vector<ll>; const int MAX = 1e5 + 5; const int MAXNODES = MAX * 4 * 17; int used; struct node{ int ln, rn, sum; } st[MAXNODES]; int build(int l, int r){ if(l == r) return ++used; int mid = l + r >> 1, cur = ++used; st[cur].ln = build(l, mid); st[cur].rn = build(mid + 1, r); return cur; } void refine(int nd){ st[nd].sum = st[st[nd].ln].sum + st[st[nd].rn].sum; } int update(int nd, int l, int r, int pos, int val){ if(l == r){ ++used; st[used].sum = st[nd].sum + val; return used; } else{ int mid = l + r >> 1, cur = ++used; st[cur].ln = st[nd].ln; st[cur].rn = st[nd].rn; if(pos <= mid) st[cur].ln = update(st[nd].ln, l, mid, pos, val); else st[cur].rn = update(st[nd].rn, mid + 1, r, pos, val); refine(cur); return cur; } } int query(int vl, int vr, int l, int r, int u, int v){ // cout << vl << ' ' << vr << ' ' << l << ' ' << r << ' ' << u << ' ' << v << '\n'; if(v < l || u > r) return 0; if(u <= l && r <= v) return st[vr].sum - st[vl].sum; int mid = l + r >> 1; return query(st[vl].ln, st[vr].ln, l, mid, u, v) + query(st[vl].rn, st[vr].rn, mid + 1, r, u, v); } struct tree2d{ int bound; vector<int> rt; vector<pair<int, int>> pts; tree2d() : rt(), pts(), bound() {} tree2d(int n, int m) : rt(n + 1), bound(m), pts() {} void add(const pair<int, int>& p){ pts.emplace_back(p); } void construct(){ if(bound == 0) return; sort(all(pts)); // for(auto [x, y] : pts){ // cout << x << ' ' << y << '\n'; // } // cout << '\n'; rt[0] = build(1, bound); for(int i = 1, j = 0; i < sz(rt); ++i){ rt[i] = rt[i - 1]; while(j < sz(pts) && pts[j].first == i){ rt[i] = update(rt[i], 1, bound, pts[j].second, +1); ++j; } } } int query2d(int l, int r, int u, int v){ if(l > r || u > v) return 0; return query(rt[l - 1], rt[r], 1, bound, u, v); } } horizontal_edges, vertical_edges, vertices, blocks; int min_x, max_x, min_y, max_y; void init(int R, int C, int x, int y, int M, char *S) { set<pair<int, int>> rivers; min_x = 1e9; max_x = -1e9; min_y = 1e9; max_y = -1e9; for(int i = 0; i <= M; ++i){ rivers.insert({x, y}); minimize(min_x, x); maximize(max_x, x); minimize(min_y, y); maximize(max_y, y); if(i < M){ if(S[i] == 'N') --x; if(S[i] == 'S') ++x; if(S[i] == 'W') --y; if(S[i] == 'E') ++y; } } horizontal_edges = tree2d(R, C); vertical_edges = tree2d(R, C); vertices = tree2d(R, C); blocks = tree2d(R, C); for(auto [x, y] : rivers){ vertices.add({x, y}); //(x + 1, y) -> vertical bool vert = false, horz = false; if(rivers.count({x + 1, y})){ // cout << "vertical : " << x << ' ' << y << ' ' << x + 1 << ' ' << y << '\n'; vertical_edges.add({x, y}); vert = true; } //(x, y + 1) -> horizontal if(rivers.count({x, y + 1})){ // cout << "horizontal : " << x << ' ' << y << ' ' << x << ' ' << y + 1 << '\n'; horizontal_edges.add({x, y}); horz = true; } if(vert && horz){ blocks.add({x, y}); } } horizontal_edges.construct(); vertical_edges.construct(); vertices.construct(); blocks.construct(); } int count_vertices(int x1, int y1, int x2, int y2){ int cur = vertices.query2d(x1, x2, y1, y2); int side = ((x2 - x1 + 1) + (y2 - y1 + 1)) * 2 + 4; return cur + side; } int count_edges(int x1, int y1, int x2, int y2){ int side = ((x2 - x1 + 1) + (y2 - y1 + 1)) * 2 + 4; // cout << dbg(side) << '\n'; int horz = horizontal_edges.query2d(x1, x2, y1, y2 - 1); int vert = vertical_edges.query2d(x1, x2 - 1, y1, y2); int left_side = vertices.query2d(x1, x1, y1, y2); int right_side = vertices.query2d(x2, x2, y1, y2); // cout << x2 << ' ' << x2 << ' ' << y1 << ' ' << y2 << '\n'; int up_side = vertices.query2d(x1, x2, y1, y1); int down_side = vertices.query2d(x1, x2, y2, y2); // cout << dbg(horz) << dbg(vert) << dbg(left_side) << dbg(right_side) << '\n'; // cout << dbg(up_side) << dbg(down_side) << '\n'; return side + horz + vert + left_side + right_side + up_side + down_side; } int count_connected_components(int x1, int y1, int x2, int y2){ int extra = (x1 < min_x && max_x < x2 && y1 < min_y && max_y < y2); return 1 + extra; } int count_blocks(int x1, int y1, int x2, int y2){ int inside = blocks.query2d(x1, x2 - 1, y1, y2 - 1); //number of 2x1 and 1x2 boundary int l = vertical_edges.query2d(x1, x1, y1, y2 - 1); int r = vertical_edges.query2d(x2, x2, y1, y2 - 1); int d = horizontal_edges.query2d(x1, x2 - 1, y1, y1); int u = horizontal_edges.query2d(x1, x2 - 1, y2, y2); int x1y1 = vertices.query2d(x1, x1, y1, y1); int x1y2 = vertices.query2d(x1, x1, y2, y2); int x2y1 = vertices.query2d(x2, x2, y1, y1); int x2y2 = vertices.query2d(x2, x2, y2, y2); // cout << dbg(x1y1) << dbg(x1y2) << dbg(x2y1) << dbg(x2y2) << '\n'; return inside + l + r + d + u + x1y1 + x1y2 + x2y1 + x2y2; } int colour(int ar, int ac, int br, int bc){ int V = count_vertices(ar, ac, br, bc); int E = count_edges(ar, ac, br, bc); int C = count_connected_components(ar, ac, br, bc); int blocks = count_blocks(ar, ac, br, bc); // cout << V << ' ' << E << ' ' << C << ' ' << blocks << '\n'; return E - V + C - blocks; } #ifdef LOCAL int main(){ ios_base::sync_with_stdio(0); cin.tie(0); freopen("task.inp", "r", stdin); freopen("task.out", "w", stdout); int R, C, M, Q, sr, sc; cin >> R >> C >> M >> Q >> sr >> sc; char S[M]; for(int i = 0; i < M; ++i) cin >> S[i]; init(R, C, sr, sc, M, S); while(Q--){ int ar, ac, br, bc; cin >> ar >> ac >> br >> bc; cout << colour(ar, ac, br, bc) << '\n'; } return 0; } #endif // LOCAL
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...