#include<iostream>
#include<vector>
#include<set>
#include<unordered_set>
using namespace std;
inline long long get_field(long long row, long long col) { return (row << 20) + col; }
inline long long get_row(long long field) { return field >> 20; }
inline long long get_col(long long field) { return field & 1048575; }
inline long long field_up(long long field) { return get_field(get_row(field) - 1, get_col(field)); }
inline long long field_down(long long field) { return get_field(get_row(field) + 1, get_col(field)); }
inline long long field_left(long long field) { return get_field(get_row(field), get_col(field) - 1); }
inline long long field_right(long long field) { return get_field(get_row(field), get_col(field) + 1); }
unordered_set<long long> starters;
unordered_set<long long> removables;
unordered_set<long long> board;
long long counter = 0;
bool is_starter(long long field) {
if (board.count(field_up(field)) == 0 && board.count(field_down(field)) == 0) return true;
if (board.count(field_left(field)) == 0 && board.count(field_right(field)) == 0) return true;
return false;
}
bool is_removable(long long field) {
if (board.count(field) == 0) {
return true;
}
bool is_up_removable = board.count(field_up(field)) == 0 || removables.count(field_up(field));
bool is_down_removable = board.count(field_down(field)) == 0 || removables.count(field_down(field));
if (is_up_removable && is_down_removable) return true;
bool is_left_removable = board.count(field_left(field)) == 0 || removables.count(field_left(field));
bool is_right_removable = board.count(field_right(field)) == 0 || removables.count(field_right(field));
if (is_left_removable && is_right_removable) return true;
return false;
}
bool exist_but_no_removable(long long field) {
return board.count(field) && !is_removable(field);
}
long long initial_conditionally_list_add(vector<long long> &lst, long long field) {
if (board.count(field) && removables.count(field) == 0 && is_removable(field)) {
lst.push_back(field);
removables.insert(field);
return 1l;
}
return 0l;
}
void initial() {
// find starters
for (long long field : board) {
if (is_starter(field)) {
starters.insert(field);
removables.insert(field);
}
}
// BFS
vector<long long> lst(removables.begin(), removables.end());
for (int i = 0; i < lst.size(); i++) {
long long field = lst[i];
initial_conditionally_list_add(lst, field_up(field));
initial_conditionally_list_add(lst, field_down(field));
initial_conditionally_list_add(lst, field_left(field));
initial_conditionally_list_add(lst, field_right(field));
}
counter = removables.size();
}
void partial_remove(long long field) {
// find new starters
vector<long long> lst;
long long up = field_up(field);
long long down = field_down(field);
long long left = field_left(field);
long long right = field_right(field);
if (exist_but_no_removable(up) && is_removable(field_up(up))) {
lst.push_back(up);
removables.insert(up);
counter++;
}
if (exist_but_no_removable(down) && is_removable(field_down(down))) {
lst.push_back(down);
removables.insert(down);
counter++;
}
if (exist_but_no_removable(left) && is_removable(field_left(left))) {
lst.push_back(left);
removables.insert(left);
counter++;
}
if (exist_but_no_removable(right) && is_removable(field_right(right))) {
lst.push_back(right);
removables.insert(right);
counter++;
}
board.erase(field);
// BFS
for (int i = 0; i < lst.size(); i++) {
long long field = lst[i];
counter += initial_conditionally_list_add(lst, field_up(field));
counter += initial_conditionally_list_add(lst, field_down(field));
counter += initial_conditionally_list_add(lst, field_left(field));
counter += initial_conditionally_list_add(lst, field_right(field));
}
}
void partial_add_conditinally(vector<long long> &lst, unordered_set<long long> &visited, long long field) {
if (board.count(field)) {
if (!visited.count(field) && removables.count(field)) {
visited.insert(field);
lst.push_back(field);
}
}
}
void partial_add(long long field) {
// BFS to get all reachable
vector<long long> lst;
lst.push_back(field);
unordered_set<long long> visited;
visited.insert(field);
for (int i = 0; i < lst.size(); i++) {
long long acc = lst[i];
partial_add_conditinally(lst, visited, field_up(acc));
partial_add_conditinally(lst, visited, field_down(acc));
partial_add_conditinally(lst, visited, field_left(acc));
partial_add_conditinally(lst, visited, field_right(acc));
}
// create new starters
vector<long long> primers;
for (long long acc : lst) {
if (is_starter(acc)) {
primers.push_back(acc);
}
else if (removables.count(acc)) {
starters.erase(acc);
removables.erase(acc);
counter--;
}
}
// BFS
for (int i = 0; i < primers.size(); i++) {
long long acc = primers[i];
counter += initial_conditionally_list_add(primers, field_up(acc));
counter += initial_conditionally_list_add(primers, field_down(acc));
counter += initial_conditionally_list_add(primers, field_left(acc));
counter += initial_conditionally_list_add(primers, field_right(acc));
}
}
int main() {
ios_base::sync_with_stdio(0);
cin.tie(0);
int m, n, k, q;
cin >> m >> n >> k >> q;
for (int i = 0; i < k; i++) {
long long row, col;
cin >> row >> col;
board.insert(get_field(row, col));
}
initial();
cout << counter << endl;
while (q--) {
int row, col;
cin >> row >> col;
long long field = get_field(row, col);
if (board.count(field)) {
// delete
if (is_removable(field)) {
board.erase(field);
starters.erase(field);
removables.erase(field);
counter--;
cout << counter << endl;
}
else {
partial_remove(field);
cout << counter << endl;
}
}
else {
// add
board.insert(field);
if (is_starter(field)) {
starters.insert(field);
removables.insert(field);
counter++;
cout << counter << endl;
}
else {
partial_add(field);
cout << counter << endl;
}
}
}
return 0;
}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 | #include<iostream> #include<vector> #include<set> #include<unordered_set> using namespace std; inline long long get_field(long long row, long long col) { return (row << 20) + col; } inline long long get_row(long long field) { return field >> 20; } inline long long get_col(long long field) { return field & 1048575; } inline long long field_up(long long field) { return get_field(get_row(field) - 1, get_col(field)); } inline long long field_down(long long field) { return get_field(get_row(field) + 1, get_col(field)); } inline long long field_left(long long field) { return get_field(get_row(field), get_col(field) - 1); } inline long long field_right(long long field) { return get_field(get_row(field), get_col(field) + 1); } unordered_set<long long> starters; unordered_set<long long> removables; unordered_set<long long> board; long long counter = 0; bool is_starter(long long field) { if (board.count(field_up(field)) == 0 && board.count(field_down(field)) == 0) return true; if (board.count(field_left(field)) == 0 && board.count(field_right(field)) == 0) return true; return false; } bool is_removable(long long field) { if (board.count(field) == 0) { return true; } bool is_up_removable = board.count(field_up(field)) == 0 || removables.count(field_up(field)); bool is_down_removable = board.count(field_down(field)) == 0 || removables.count(field_down(field)); if (is_up_removable && is_down_removable) return true; bool is_left_removable = board.count(field_left(field)) == 0 || removables.count(field_left(field)); bool is_right_removable = board.count(field_right(field)) == 0 || removables.count(field_right(field)); if (is_left_removable && is_right_removable) return true; return false; } bool exist_but_no_removable(long long field) { return board.count(field) && !is_removable(field); } long long initial_conditionally_list_add(vector<long long> &lst, long long field) { if (board.count(field) && removables.count(field) == 0 && is_removable(field)) { lst.push_back(field); removables.insert(field); return 1l; } return 0l; } void initial() { // find starters for (long long field : board) { if (is_starter(field)) { starters.insert(field); removables.insert(field); } } // BFS vector<long long> lst(removables.begin(), removables.end()); for (int i = 0; i < lst.size(); i++) { long long field = lst[i]; initial_conditionally_list_add(lst, field_up(field)); initial_conditionally_list_add(lst, field_down(field)); initial_conditionally_list_add(lst, field_left(field)); initial_conditionally_list_add(lst, field_right(field)); } counter = removables.size(); } void partial_remove(long long field) { // find new starters vector<long long> lst; long long up = field_up(field); long long down = field_down(field); long long left = field_left(field); long long right = field_right(field); if (exist_but_no_removable(up) && is_removable(field_up(up))) { lst.push_back(up); removables.insert(up); counter++; } if (exist_but_no_removable(down) && is_removable(field_down(down))) { lst.push_back(down); removables.insert(down); counter++; } if (exist_but_no_removable(left) && is_removable(field_left(left))) { lst.push_back(left); removables.insert(left); counter++; } if (exist_but_no_removable(right) && is_removable(field_right(right))) { lst.push_back(right); removables.insert(right); counter++; } board.erase(field); // BFS for (int i = 0; i < lst.size(); i++) { long long field = lst[i]; counter += initial_conditionally_list_add(lst, field_up(field)); counter += initial_conditionally_list_add(lst, field_down(field)); counter += initial_conditionally_list_add(lst, field_left(field)); counter += initial_conditionally_list_add(lst, field_right(field)); } } void partial_add_conditinally(vector<long long> &lst, unordered_set<long long> &visited, long long field) { if (board.count(field)) { if (!visited.count(field) && removables.count(field)) { visited.insert(field); lst.push_back(field); } } } void partial_add(long long field) { // BFS to get all reachable vector<long long> lst; lst.push_back(field); unordered_set<long long> visited; visited.insert(field); for (int i = 0; i < lst.size(); i++) { long long acc = lst[i]; partial_add_conditinally(lst, visited, field_up(acc)); partial_add_conditinally(lst, visited, field_down(acc)); partial_add_conditinally(lst, visited, field_left(acc)); partial_add_conditinally(lst, visited, field_right(acc)); } // create new starters vector<long long> primers; for (long long acc : lst) { if (is_starter(acc)) { primers.push_back(acc); } else if (removables.count(acc)) { starters.erase(acc); removables.erase(acc); counter--; } } // BFS for (int i = 0; i < primers.size(); i++) { long long acc = primers[i]; counter += initial_conditionally_list_add(primers, field_up(acc)); counter += initial_conditionally_list_add(primers, field_down(acc)); counter += initial_conditionally_list_add(primers, field_left(acc)); counter += initial_conditionally_list_add(primers, field_right(acc)); } } int main() { ios_base::sync_with_stdio(0); cin.tie(0); int m, n, k, q; cin >> m >> n >> k >> q; for (int i = 0; i < k; i++) { long long row, col; cin >> row >> col; board.insert(get_field(row, col)); } initial(); cout << counter << endl; while (q--) { int row, col; cin >> row >> col; long long field = get_field(row, col); if (board.count(field)) { // delete if (is_removable(field)) { board.erase(field); starters.erase(field); removables.erase(field); counter--; cout << counter << endl; } else { partial_remove(field); cout << counter << endl; } } else { // add board.insert(field); if (is_starter(field)) { starters.insert(field); removables.insert(field); counter++; cout << counter << endl; } else { partial_add(field); cout << counter << endl; } } } return 0; } |
English