// clang-format off
#include<bits/stdc++.h>
using namespace std;
using LL=long long;
#define FOR(i,l,r) for(auto i=(l);i<=(r);++i)
#define REP(i,n) FOR(i,0,(n)-1)
#define ssize(x) int(x.size())
auto operator<<(ostream&o,auto x)->decltype(x.end(),o);
auto operator<<(ostream&o,auto p)->decltype(p.first,o){return o<<"("<<p.first<<", "<<p.second<<")";}
auto operator<<(ostream&o,auto x)->decltype(x.end(),o){o<<"{";int i=0;for(auto e:x)o<<(", ")+2*!i++<<e;return o<<"}";}
#ifdef DEBUG
#define log(x) cerr<<x<<"\n"
#define debug(x...) cerr<<"["#x"]: ",[](auto...$){((cerr<<$<<"; "),...);}(x),cerr<<'\n'
#else
#define log(...) {}
#define debug(...) {}
#endif
// clang-format on
int nverts, nedges, ncolors;
vector<int> vert_color;
vector<pair<int, int>> edges;
struct DSU
{
// Sets in this DSU divide into two categories:
//
// - color_roots: connected components, where all vertices in component are
// of the same color; when vertices are inside such a color root set, it
// means that at the current stage of algorithm, I can get to every vertex
// in the set
// - areas: connected components, which contain all vertices of given set of
// color
// Data for DSU itself
vector<int> parent, set_size;
// Data for color roots
vector<int> set_color;
vector<set<int>> color_roots; // leaders of sets of each color
vector<vector<int>> set_adj; // neighbours are of a different color
// Data for areas
vector<int> make_arena_inbox;
vector<map<int, int>> area_adj; // (color, color root)
DSU(int nverts,
int ncolors,
const vector<int> &vert_color,
const vector<pair<int, int>> &edges)
: parent(nverts + 1)
, set_size(nverts + 1, 1)
, set_color(vert_color)
, color_roots(ncolors + 1)
, set_adj(nverts + 1)
, area_adj(nverts + 1)
{
iota(parent.begin(), parent.end(), 0);
REP (v, ssize(vert_color)) color_roots[vert_color[v]].insert(v);
for (const auto &edge : edges) {
const auto &[a, b] = edge;
if (vert_color[a] == vert_color[b]) continue;
set_adj[a].emplace_back(b);
set_adj[b].emplace_back(a);
}
// Make areas out of colors being singletons
FOR (color, 1, ncolors) {
if (color_roots[color].size() != 1) continue;
auto root = *color_roots[color].begin();
make_arena_inbox.emplace_back(root);
}
}
int find_leader(int v)
{
if (parent[v] == v) return v;
return parent[v] = find_leader(parent[v]);
}
void merge_color_roots(int a, int b)
{
a = find_leader(a), b = find_leader(b);
if (a == b) return;
debug("merge", a, b);
// Assert that these are indeed different color roots
assert(set_color[a] == set_color[b]);
auto color = set_color[a];
// Make a smaller (so we marge a into b)
if (set_size[a] > set_size[b]) swap(a, b);
// a is no longer a color root
color_roots[color].erase(a);
// Perform the merge
set_size[b] += set_size[a];
set_size[a] = 0;
merge_adj(set_adj[a], set_adj[b]);
parent[a] = b;
// Maybe we became an area?
if (is_area_candidate(b)) make_arena_inbox.emplace_back(b);
}
void merge_adj(vector<int> &from, vector<int> &into)
{
if (ssize(from) > ssize(into)) swap(from, into);
into.reserve(into.size() + from.size());
for (const auto &entry : from) into.emplace_back(entry);
}
void make_area(int v)
{
if (is_area(v)) return;
v = find_leader(v);
assert(is_area_candidate(v));
debug("make_area", v);
vector<int> neigh_areas; // merge them into me at the end
auto neighbours = std::move(set_adj[v]);
assert(is_area(v));
for (const auto &neigh : neighbours) {
assert(v == find_leader(v));
if (v == find_leader(neigh)) continue;
if (is_area(neigh)) {
neigh_areas.emplace_back(neigh);
continue;
}
if (is_area_candidate(neigh)) {
make_arena_inbox.emplace_back(neigh);
continue;
}
// neigh is just a color root now
auto root = find_leader(neigh);
auto color = set_color[root];
auto it = area_adj[v].find(color);
if (it == area_adj[v].end()) {
area_adj[v][color] = root;
continue;
}
// we merge our neighbouring color roots
auto merge_into = it->second;
merge_color_roots(root, merge_into);
assert(v == find_leader(v));
it->second = find_leader(root);
}
// Merge neighbouring areas with me
assert(v == find_leader(v));
for (const auto &neigh : neigh_areas) {
merge_area(neigh, v);
v = find_leader(v);
}
}
void merge_area(int a, int b)
{
a = find_leader(a), b = find_leader(b);
if (a == b) return;
debug("merge_area", a, b);
assert(is_area(a) and is_area(b));
assert(set_color[a] != set_color[b]);
if (set_size[a] > set_size[b]) swap(a, b);
color_roots[set_color[a]].erase(a);
set_size[b] += set_size[a];
set_size[a] = 0;
parent[a] = b;
merge_area_adj(area_adj[a], area_adj[b]);
}
void merge_area_adj(map<int, int> &from, map<int, int> &into)
{
if (ssize(from) > ssize(into)) swap(from, into);
for (const auto &entry : from) {
const auto &[color, root] = entry;
auto it = into.find(color);
if (it == into.end()) {
into[color] = root;
continue;
}
auto other = it->second;
merge_color_roots(root, other);
it->second = find_leader(root);
}
from.clear();
}
inline bool is_area_candidate(int v)
{
return color_roots[set_color[find_leader(v)]].size() == 1;
}
inline bool is_area(int v)
{
return is_area_candidate(v) && set_adj[find_leader(v)].empty();
}
};
unique_ptr<DSU> dsu;
void input();
ostream &operator<<(ostream &o, DSU &dsu);
bool
solve()
{
input();
debug(*dsu.get());
log("\nAdding edges between the same color");
for (const auto &edge : edges) {
const auto &[a, b] = edge;
if (vert_color[a] != vert_color[b]) continue;
debug(vert_color[a], a, b);
dsu->merge_color_roots(a, b);
debug(*dsu.get());
}
// Merge all areas
log("\nMerging areas");
while (!dsu->make_arena_inbox.empty()) {
auto v = dsu->make_arena_inbox.back();
dsu->make_arena_inbox.pop_back();
if (dsu->is_area(v)) continue;
dsu->make_area(v);
debug(*dsu.get());
log("");
}
debug(dsu->set_size);
debug(dsu->color_roots);
return nverts == *max_element(dsu->set_size.begin(), dsu->set_size.end());
}
int
main()
{
cin.tie(0)->sync_with_stdio(0);
int ntests;
cin >> ntests;
while (ntests--) {
log("\n============================= Test Case =============================");
cout << (solve() ? "TAK\n" : "NIE\n");
}
return 0;
}
void
input()
{
cin >> nverts >> nedges >> ncolors;
vert_color.resize(nverts + 1);
FOR (v, 1, nverts) {
cin >> vert_color[v];
}
edges.resize(nedges);
for (auto &edge : edges) cin >> edge.first >> edge.second;
mt19937 rng(123498172);
shuffle(edges.begin(), edges.end(), rng);
dsu.reset(new DSU(nverts, ncolors, vert_color, edges));
}
ostream &
operator<<(ostream &o, DSU &dsu)
{
map<int, vector<int>> sets;
FOR (v, 1, nverts)
if (dsu.find_leader(v) == v) sets[v].emplace_back(v);
FOR (v, 1, nverts)
if (dsu.find_leader(v) != v) sets[dsu.find_leader(v)].emplace_back(v);
o << "[";
int i = 0;
for (const auto &s : sets) o << (", ") + 2 * !i++ << s.second;
o << "]";
return o;
}
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 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 | // clang-format off #include<bits/stdc++.h> using namespace std; using LL=long long; #define FOR(i,l,r) for(auto i=(l);i<=(r);++i) #define REP(i,n) FOR(i,0,(n)-1) #define ssize(x) int(x.size()) auto operator<<(ostream&o,auto x)->decltype(x.end(),o); auto operator<<(ostream&o,auto p)->decltype(p.first,o){return o<<"("<<p.first<<", "<<p.second<<")";} auto operator<<(ostream&o,auto x)->decltype(x.end(),o){o<<"{";int i=0;for(auto e:x)o<<(", ")+2*!i++<<e;return o<<"}";} #ifdef DEBUG #define log(x) cerr<<x<<"\n" #define debug(x...) cerr<<"["#x"]: ",[](auto...$){((cerr<<$<<"; "),...);}(x),cerr<<'\n' #else #define log(...) {} #define debug(...) {} #endif // clang-format on int nverts, nedges, ncolors; vector<int> vert_color; vector<pair<int, int>> edges; struct DSU { // Sets in this DSU divide into two categories: // // - color_roots: connected components, where all vertices in component are // of the same color; when vertices are inside such a color root set, it // means that at the current stage of algorithm, I can get to every vertex // in the set // - areas: connected components, which contain all vertices of given set of // color // Data for DSU itself vector<int> parent, set_size; // Data for color roots vector<int> set_color; vector<set<int>> color_roots; // leaders of sets of each color vector<vector<int>> set_adj; // neighbours are of a different color // Data for areas vector<int> make_arena_inbox; vector<map<int, int>> area_adj; // (color, color root) DSU(int nverts, int ncolors, const vector<int> &vert_color, const vector<pair<int, int>> &edges) : parent(nverts + 1) , set_size(nverts + 1, 1) , set_color(vert_color) , color_roots(ncolors + 1) , set_adj(nverts + 1) , area_adj(nverts + 1) { iota(parent.begin(), parent.end(), 0); REP (v, ssize(vert_color)) color_roots[vert_color[v]].insert(v); for (const auto &edge : edges) { const auto &[a, b] = edge; if (vert_color[a] == vert_color[b]) continue; set_adj[a].emplace_back(b); set_adj[b].emplace_back(a); } // Make areas out of colors being singletons FOR (color, 1, ncolors) { if (color_roots[color].size() != 1) continue; auto root = *color_roots[color].begin(); make_arena_inbox.emplace_back(root); } } int find_leader(int v) { if (parent[v] == v) return v; return parent[v] = find_leader(parent[v]); } void merge_color_roots(int a, int b) { a = find_leader(a), b = find_leader(b); if (a == b) return; debug("merge", a, b); // Assert that these are indeed different color roots assert(set_color[a] == set_color[b]); auto color = set_color[a]; // Make a smaller (so we marge a into b) if (set_size[a] > set_size[b]) swap(a, b); // a is no longer a color root color_roots[color].erase(a); // Perform the merge set_size[b] += set_size[a]; set_size[a] = 0; merge_adj(set_adj[a], set_adj[b]); parent[a] = b; // Maybe we became an area? if (is_area_candidate(b)) make_arena_inbox.emplace_back(b); } void merge_adj(vector<int> &from, vector<int> &into) { if (ssize(from) > ssize(into)) swap(from, into); into.reserve(into.size() + from.size()); for (const auto &entry : from) into.emplace_back(entry); } void make_area(int v) { if (is_area(v)) return; v = find_leader(v); assert(is_area_candidate(v)); debug("make_area", v); vector<int> neigh_areas; // merge them into me at the end auto neighbours = std::move(set_adj[v]); assert(is_area(v)); for (const auto &neigh : neighbours) { assert(v == find_leader(v)); if (v == find_leader(neigh)) continue; if (is_area(neigh)) { neigh_areas.emplace_back(neigh); continue; } if (is_area_candidate(neigh)) { make_arena_inbox.emplace_back(neigh); continue; } // neigh is just a color root now auto root = find_leader(neigh); auto color = set_color[root]; auto it = area_adj[v].find(color); if (it == area_adj[v].end()) { area_adj[v][color] = root; continue; } // we merge our neighbouring color roots auto merge_into = it->second; merge_color_roots(root, merge_into); assert(v == find_leader(v)); it->second = find_leader(root); } // Merge neighbouring areas with me assert(v == find_leader(v)); for (const auto &neigh : neigh_areas) { merge_area(neigh, v); v = find_leader(v); } } void merge_area(int a, int b) { a = find_leader(a), b = find_leader(b); if (a == b) return; debug("merge_area", a, b); assert(is_area(a) and is_area(b)); assert(set_color[a] != set_color[b]); if (set_size[a] > set_size[b]) swap(a, b); color_roots[set_color[a]].erase(a); set_size[b] += set_size[a]; set_size[a] = 0; parent[a] = b; merge_area_adj(area_adj[a], area_adj[b]); } void merge_area_adj(map<int, int> &from, map<int, int> &into) { if (ssize(from) > ssize(into)) swap(from, into); for (const auto &entry : from) { const auto &[color, root] = entry; auto it = into.find(color); if (it == into.end()) { into[color] = root; continue; } auto other = it->second; merge_color_roots(root, other); it->second = find_leader(root); } from.clear(); } inline bool is_area_candidate(int v) { return color_roots[set_color[find_leader(v)]].size() == 1; } inline bool is_area(int v) { return is_area_candidate(v) && set_adj[find_leader(v)].empty(); } }; unique_ptr<DSU> dsu; void input(); ostream &operator<<(ostream &o, DSU &dsu); bool solve() { input(); debug(*dsu.get()); log("\nAdding edges between the same color"); for (const auto &edge : edges) { const auto &[a, b] = edge; if (vert_color[a] != vert_color[b]) continue; debug(vert_color[a], a, b); dsu->merge_color_roots(a, b); debug(*dsu.get()); } // Merge all areas log("\nMerging areas"); while (!dsu->make_arena_inbox.empty()) { auto v = dsu->make_arena_inbox.back(); dsu->make_arena_inbox.pop_back(); if (dsu->is_area(v)) continue; dsu->make_area(v); debug(*dsu.get()); log(""); } debug(dsu->set_size); debug(dsu->color_roots); return nverts == *max_element(dsu->set_size.begin(), dsu->set_size.end()); } int main() { cin.tie(0)->sync_with_stdio(0); int ntests; cin >> ntests; while (ntests--) { log("\n============================= Test Case ============================="); cout << (solve() ? "TAK\n" : "NIE\n"); } return 0; } void input() { cin >> nverts >> nedges >> ncolors; vert_color.resize(nverts + 1); FOR (v, 1, nverts) { cin >> vert_color[v]; } edges.resize(nedges); for (auto &edge : edges) cin >> edge.first >> edge.second; mt19937 rng(123498172); shuffle(edges.begin(), edges.end(), rng); dsu.reset(new DSU(nverts, ncolors, vert_color, edges)); } ostream & operator<<(ostream &o, DSU &dsu) { map<int, vector<int>> sets; FOR (v, 1, nverts) if (dsu.find_leader(v) == v) sets[v].emplace_back(v); FOR (v, 1, nverts) if (dsu.find_leader(v) != v) sets[dsu.find_leader(v)].emplace_back(v); o << "["; int i = 0; for (const auto &s : sets) o << (", ") + 2 * !i++ << s.second; o << "]"; return o; } |
English