QOJ.ac
QOJ
ID | Problem | Submitter | Result | Time | Memory | Language | File size | Submit time | Judge time |
---|---|---|---|---|---|---|---|---|---|
#330091 | #8055. Balance | ucup-team3099# | WA | 233ms | 3872kb | C++23 | 17.3kb | 2024-02-17 12:15:11 | 2024-02-17 12:15:11 |
Judging History
answer
// #pragma GCC optimize("O3,unroll-loops")
#include <bits/stdc++.h>
// #include <x86intrin.h>
using namespace std;
#if __cplusplus >= 202002L
using namespace numbers;
#endif
template<class T>
struct graph{
using Weight_t = T;
struct Edge_t{
int from, to;
T cost;
};
int n;
vector<Edge_t> edge;
vector<vector<int>> adj;
function<bool(int)> ignore;
graph(int n = 1): n(n), adj(n){
assert(n >= 1);
}
graph(const vector<vector<int>> &adj, bool undirected = true): n((int)adj.size()), adj(n){
assert(n >= 1);
if(undirected){
for(auto u = 0; u < n; ++ u) for(auto v: adj[u]) if(u < v) link(u, v);
}
else for(auto u = 0; u < n; ++ u) for(auto v: adj[u]) orient(u, v);
}
graph(const vector<vector<pair<int, T>>> &adj, bool undirected = true): n((int)adj.size()), adj(n){
assert(n >= 1);
if(undirected){
for(auto u = 0; u < n; ++ u) for(auto [v, w]: adj[u]) if(u < v) link(u, v, w);
}
else for(auto u = 0; u < n; ++ u) for(auto [v, w]: adj[u]) orient(u, v, w);
}
graph(int n, vector<array<int, 2>> &edge, bool undirected = true): n(n), adj(n){
assert(n >= 1);
for(auto [u, v]: edge) undirected ? link(u, v) : orient(u, v);
}
graph(int n, vector<tuple<int, int, T>> &edge, bool undirected = true): n(n), adj(n){
assert(n >= 1);
for(auto [u, v, w]: edge) undirected ? link(u, v, w) : orient(u, v, w);
}
int operator()(int u, int id) const{
#ifdef LOCAL
assert(0 <= id && id < (int)edge.size());
assert(edge[id].from == u || edge[id].to == u);
#endif
return u ^ edge[id].from ^ edge[id].to;
}
int link(int u, int v, T w = {}){ // insert an undirected edge
int id = (int)edge.size();
adj[u].push_back(id), adj[v].push_back(id), edge.push_back({u, v, w});
return id;
}
int orient(int u, int v, T w = {}){ // insert a directed edge
int id = (int)edge.size();
adj[u].push_back(id), edge.push_back({u, v, w});
return id;
}
void clear(){
for(auto [u, v, w]: edge){
adj[u].clear();
adj[v].clear();
}
edge.clear();
ignore = {};
}
graph transposed() const{ // the transpose of the directed graph
graph res(n);
for(auto &e: edge) res.orient(e.to, e.from, e.cost);
res.ignore = ignore;
return res;
}
int degree(int u) const{ // the degree (outdegree if directed) of u (without the ignoration rule)
return (int)adj[u].size();
}
// The adjacency list is sorted for each vertex.
vector<vector<int>> get_adjacency_list() const{
vector<vector<int>> res(n);
for(auto u = 0; u < n; ++ u) for(auto id: adj[u]){
if(ignore && ignore(id)) continue;
res[(*this)(u, id)].push_back(u);
}
return res;
}
void set_ignoration_rule(const function<bool(int)> &f){
ignore = f;
}
void reset_ignoration_rule(){
ignore = nullptr;
}
friend ostream &operator<<(ostream &out, const graph &g){
for(auto id = 0; id < (int)g.edge.size(); ++ id){
if(g.ignore && g.ignore(id)) continue;
auto &e = g.edge[id];
out << "{" << e.from << ", " << e.to << ", " << e.cost << "}\n";
}
return out;
}
};
// Requires graph
template<class T>
struct dfs_forest{
int n;
T base_dist;
vector<T> dist;
vector<int> pv;
vector<int> pe;
vector<int> order;
vector<int> pos;
vector<int> end;
vector<int> size;
vector<int> root_of;
vector<int> root;
vector<int> depth;
vector<int> min_depth;
vector<int> min_depth_origin;
vector<int> min_depth_spanning_edge;
// extra_edge[u]: adjacent edges of u which is not part of the spanning forest found during the last dfs-like run.
vector<vector<int>> extra_edge;
vector<int> was;
dfs_forest(T base_dist = 0): base_dist(base_dist){ }
void init(int n){
this->n = n;
pv.assign(n, -1);
pe.assign(n, -1);
order.clear();
pos.assign(n, -1);
end.assign(n, -1);
size.assign(n, 0);
root_of.assign(n, -1);
root.clear();
depth.assign(n, -1);
min_depth.assign(n, -1);
min_depth_origin.assign(n, -1);
min_depth_spanning_edge.assign(n, -1);
dist.assign(n, base_dist);
extra_edge.assign(n, {});
was.assign(n, -2);
attempt = -1;
}
int attempt;
// O(# of nodes reachable from u)
template<class U, class F = plus<>>
void _dfs(const graph<U> &g, int u, F UT = plus<>()){
depth[u] = 0;
dist[u] = base_dist;
root_of[u] = u;
root.push_back(u);
pv[u] = pe[u] = -1;
auto recurse = [&](auto self, int u)->void{
was[u] = attempt;
pos[u] = (int)order.size();
order.push_back(u);
size[u] = 1;
min_depth[u] = depth[u];
min_depth_origin[u] = u;
min_depth_spanning_edge[u] = -1;
for(auto id: g.adj[u]){
if(id == pe[u] || g.ignore && g.ignore(id)) continue;
int v = g(u, id);
if(was[v] == attempt){
if(min_depth[u] > depth[v]){
min_depth[u] = depth[v];
min_depth_spanning_edge[u] = id;
}
if(pe[u] != id) extra_edge[u].push_back(id);
continue;
}
depth[v] = depth[u] + 1;
dist[v] = UT(g.edge[id].cost, dist[u]);
pv[v] = u;
pe[v] = id;
root_of[v] = root_of[u];
self(self, v);
size[u] += size[v];
if(min_depth[u] > min_depth[v]){
min_depth[u] = min_depth[v];
min_depth_origin[u] = min_depth_origin[v];
min_depth_spanning_edge[u] = min_depth_spanning_edge[v];
}
}
end[u] = (int)order.size();
};
recurse(recurse, u);
}
// O(# of nodes reachable from src)
template<class U, class F = plus<>>
void dfs(const graph<U> &g, const vector<int> &src, F UT = plus<>()){
assert(g.n <= n);
root.clear(), order.clear();
++ attempt;
for(auto u: src){
assert(0 <= u && u < g.n);
if(was[u] != attempt) _dfs(g, u, UT);
}
}
// O(n + m)
template<class U, class F = plus<>>
void dfs_all(const graph<U> &g, F UT = plus<>()){
assert(g.n <= n);
root.clear(), order.clear();
++ attempt;
for(auto u = 0; u < g.n; ++ u) if(was[u] != attempt) _dfs(g, u, UT);
}
// Check if u is visited during the last dfs-like call.
bool visited(int u) const{
assert(0 <= u && u < n);
return was[u] == attempt;
}
// Check if u is an ancestor of v in some spanning tree.
bool ancestor_of(int u, int v) const{
assert(visited(u) && visited(v));
return pos[u] <= pos[v] && end[v] <= end[u];
}
// Check if any cycle is found during the last dfs-like call.
// If must_contain_root = true, the sought cycle is forced to contain one of the root of the trees.
template<class U>
optional<pair<int, vector<int>>> find_any_cycle(const graph<U> &g, bool must_contain_root = false) const{
for(auto u: order) for(auto id: extra_edge[u]){
int v = g(u, id);
if(!ancestor_of(v, u) || must_contain_root && root_of[v] != v) continue;
vector<int> cycle_edge;
while(u != v) cycle_edge.push_back(pe[u]), u = pv[u];
reverse(cycle_edge.begin(), cycle_edge.end());
cycle_edge.push_back(id);
return pair{v, cycle_edge};
}
return {};
}
};
// Requires graph
struct biconnected_components{
int n, attempt, comp_attempt;
vector<int> pos;
vector<int> stack;
vector<int> was;
vector<int> comp_was;
// block-cut tree descriptions
vector<vector<int>> belongs; // vertex -> list of 2-vertex-connected components
vector<vector<int>> comp_vertex; // list of vertices in a 2-vertex-connected component
vector<vector<int>> comp_edge; // list of edges in a 2-vertex-connected component
vector<int> bridge;
void init(int n){
this->n = n;
pos.assign(n, -1);
was.assign(n, -2);
attempt = -1;
comp_was.assign(n, -2);
comp_attempt = -1;
belongs.assign(n, {});
comp_vertex.clear();
comp_edge.clear();
bridge.clear();
}
// O(n + m) where n and m are the number of reachable nodes and edges respectively.
template<class T>
void _run(const graph<T> &g, const vector<int> &src){
int it = 0;
auto recurse = [&](auto self, int u, int pe)->int{
int low = pos[u] = ++ it;
belongs[u].clear();
was[u] = attempt;
for(auto id: g.adj[u]){
if(g.ignore && g.ignore(id) || id == pe) continue;
int v = g(u, id);
if(was[v] != attempt){
was[v] = attempt;
pos[v] = 0;
}
if(pos[v]){
low = min(low, pos[v]);
if(pos[v] < pos[u]) stack.push_back(id);
}
else{
int size = (int)stack.size(), up = self(self, v, id);
low = min(low, up);
if(up == pos[u]){
++ comp_attempt;
stack.push_back(id);
vector<int> comp_v;
vector<int> comp_e(stack.begin() + size, stack.end());
for(auto id: comp_e){
auto [u, v, _] = g.edge[id];
if(comp_was[u] != comp_attempt){
comp_was[u] = comp_attempt;
comp_v.push_back(u);
}
if(comp_was[v] != comp_attempt){
comp_was[v] = comp_attempt;
comp_v.push_back(v);
}
}
for(auto u: comp_v) belongs[u].push_back((int)comp_vertex.size());
comp_vertex.push_back(move(comp_v));
comp_edge.push_back(move(comp_e));
stack.resize(size);
}
else if(up < pos[u]) stack.push_back(id);
else{
belongs[g.edge[id].from].push_back((int)comp_vertex.size());
belongs[g.edge[id].to].push_back((int)comp_vertex.size());
comp_vertex.push_back({g.edge[id].from, g.edge[id].to});
comp_edge.push_back({id});
bridge.push_back(id);
}
}
}
return low;
};
for(auto u: src) if(was[u] != attempt) recurse(recurse, u, -1);
}
template<class T>
void run(const graph<T> &g, const vector<int> &src){
assert(g.n <= n);
for(auto u: src) assert(0 <= u && u < g.n);
comp_vertex.clear();
comp_edge.clear();
bridge.clear();
++ attempt;
_run(g, src);
}
template<class T>
void run_all(const graph<T> &g){
assert(g.n <= n);
comp_vertex.clear();
comp_edge.clear();
bridge.clear();
++ attempt;
vector<int> src(g.n);
iota(src.begin(), src.end(), 0);
_run(g, src);
}
// Check if u is visited during the last run-like call.
bool visited(int u) const{
assert(0 <= u && u < n);
return was[u] == attempt;
}
bool is_articulation_point(int u) const{
assert(0 <= u && u < n && visited(n));
return (int)belongs[u].size() >= 2;
}
bool is_bridge_component(int i) const{
assert(0 <= i && i < (int)comp_vertex.size());
return (int)comp_edge[i].size() == 1;
}
// # of 2-vertex-connected components
int count() const{
return (int)comp_vertex.size();
}
};
template<bool Enable_small_to_large = true>
struct disjoint_set{
int n, _group_count;
vector<int> p;
vector<list<int>> group;
disjoint_set(){ }
disjoint_set(int n): n(n), _group_count(n), p(n, -1), group(n){ assert(n >= 0);
for(auto i = 0; i < n; ++ i) group[i] = {i};
}
int make_set(){
p.push_back(-1);
group.push_back(list<int>{p});
++ _group_count;
return n ++;
}
int root(int u){
return p[u] < 0 ? u : p[u] = root(p[u]);
}
bool share(int a, int b){
return root(a) == root(b);
}
int size(int u){
return -p[root(u)];
}
bool merge(int u, int v){
u = root(u), v = root(v);
if(u == v) return false;
-- _group_count;
if constexpr(Enable_small_to_large) if(p[u] > p[v]) swap(u, v);
p[u] += p[v], p[v] = u;
group[u].splice(group[u].end(), group[v]);
return true;
}
bool merge(int u, int v, auto act){
u = root(u), v = root(v);
if(u == v) return false;
-- _group_count;
bool swapped = false;
if constexpr(Enable_small_to_large) if(p[u] > p[v]) swap(u, v), swapped = true;
p[u] += p[v], p[v] = u;
group[u].splice(group[u].end(), group[v]);
act(u, v, swapped);
return true;
}
int group_count() const{
return _group_count;
}
const list<int> &group_of(int u){
return group[root(u)];
}
vector<vector<int>> group_up(){
vector<vector<int>> g(n);
for(auto i = 0; i < n; ++ i) g[root(i)].push_back(i);
g.erase(remove_if(g.begin(), g.end(), [&](auto &s){ return s.empty(); }), g.end());
return g;
}
void clear(){
_group_count = n;
fill(p.begin(), p.end(), -1);
for(auto i = 0; i < n; ++ i) group[i] = {i};
}
friend ostream &operator<<(ostream &out, disjoint_set dsu){
auto gs = dsu.group_up();
out << "{";
if(!gs.empty()) for(auto i = 0; i < (int)gs.size(); ++ i){
out << "{";
for(auto j = 0; j < (int)gs[i].size(); ++ j){
out << gs[i][j];
if(j + 1 < (int)gs[i].size()) out << ", ";
}
out << "}";
if(i + 1 < (int)gs.size()) out << ", ";
}
return out << "}";
}
};
int main(){
cin.tie(0)->sync_with_stdio(0);
cin.exceptions(ios::badbit | ios::failbit);
biconnected_components bcc;
dfs_forest<int> df;
auto __solve_tc = [&](auto __tc_num)->int{
int n, m;
cin >> n >> m;
graph<int> g(n);
for(auto i = 0; i < m; ++ i){
int u, v;
cin >> u >> v, -- u, -- v;
g.link(u, v, 1);
}
vector<pair<int, int>> cnt;
{
map<int, int> _cnt;
for(auto u = 0; u < n; ++ u){
int x;
cin >> x;
++ _cnt[x];
}
cnt = {_cnt.begin(), _cnt.end()};
}
vector<int> cut;
{
int pref = 0;
for(auto it = cnt.begin(); next(it) != cnt.end(); ++ it){
cut.push_back(pref += it->second);
}
}
int k = (int)cut.size();
bcc.init(n);
bcc.run_all(g);
disjoint_set dsu(n);
vector<int> is_bridge(m);
for(auto id: bcc.bridge){
is_bridge[id] = true;
}
for(auto id = 0; id < m; ++ id){
if(!is_bridge[id]){
auto [u, v, _] = g.edge[id];
dsu.merge(u, v);
}
}
vector<vector<int>> comp = dsu.group_up();
vector<int> belong(n, -1);
for(auto i = 0; i < (int)comp.size(); ++ i){
for(auto u: comp[i]){
belong[u] = i;
}
}
graph<int> h((int)comp.size());
for(auto id: bcc.bridge){
auto [u, v, _] = g.edge[id];
h.link(belong[u], belong[v]);
}
vector<int> size((int)comp.size());
for(auto i = 0; i < (int)comp.size(); ++ i){
size[i] = (int)comp[i].size();
}
df.init((int)comp.size());
df.dfs(h, {0});
for(auto &[u, v, _]: h.edge){
if(df.depth[u] < df.depth[v]){
swap(u, v);
}
}
for(auto i: df.order | ranges::views::drop(1) | ranges::views::reverse){
size[df.pv[i]] += size[i];
}
vector<int> dp_up((int)comp.size());
vector<int> dp_down((int)comp.size());
vector<int> prev_up((int)comp.size(), -1);
vector<int> prev_down((int)comp.size(), -1);
vector<int> res_cut((int)h.edge.size());
for(auto i: df.order | ranges::views::reverse){
for(auto id: h.adj[i]){
if(id == df.pe[i]){
continue;
}
int j = h(i, id);
assert(dp_up[i] + dp_down[j] <= k);
assert(dp_down[i] + dp_up[j] <= k);
vector<int> seq;
if(dp_up[i] + dp_down[j] == k){
for(auto u = i; ~prev_up[u]; ){
int id = prev_up[u];
res_cut[id] = true;
seq.push_back(u = h.edge[id].from);
}
ranges::reverse(seq);
seq.push_back(i);
for(auto u = j; ~prev_down[u]; ){
int id = prev_down[u];
res_cut[id] = true;
seq.push_back(u = h.edge[id].from);
}
}
else if(dp_up[i] + dp_down[j] == k - 1 && size[j] == n - cut[dp_up[i]]){
for(auto u = i; ~prev_up[u]; ){
int id = prev_up[u];
res_cut[id] = true;
seq.push_back(u = h.edge[id].from);
}
ranges::reverse(seq);
seq.push_back(i);
res_cut[id] = true;
seq.push_back(j);
for(auto u = j; ~prev_down[u]; ){
int id = prev_down[u];
res_cut[id] = true;
seq.push_back(u = h.edge[id].from);
}
}
else if(dp_down[i] + dp_up[j] == k){
for(auto u = i; ~prev_down[u]; ){
int id = prev_down[u];
res_cut[id] = true;
seq.push_back(u = h.edge[id].from);
}
int _size = (int)seq.size();
seq.push_back(i);
for(auto u = j; ~prev_up[u]; ){
int id = prev_up[u];
res_cut[id] = true;
seq.push_back(u = h.edge[id].from);
}
ranges::reverse(seq | ranges::views::drop(_size));
}
else if(dp_down[i] + dp_up[j] == k - 1 && size[j] == cut[dp_up[j]]){
for(auto u = i; ~prev_down[u]; ){
int id = prev_down[u];
res_cut[id] = true;
seq.push_back(u = h.edge[id].from);
}
int _size = (int)seq.size();
seq.push_back(i);
res_cut[id] = true;
seq.push_back(j);
for(auto u = j; ~prev_up[u]; ){
int id = prev_up[u];
res_cut[id] = true;
seq.push_back(u = h.edge[id].from);
}
ranges::reverse(seq | ranges::views::drop(_size));
}
else{
if(dp_up[i] < dp_up[j] + (size[j] == cut[dp_up[j]])){
dp_up[i] = dp_up[j] + (size[j] == cut[dp_up[j]]);
prev_up[i] = size[j] == cut[dp_up[j]] ? id : prev_up[j];
}
if(dp_down[i] < dp_down[j] + (size[j] == n - cut[k - 1 - dp_down[j]])){
dp_down[i] = dp_down[j] + (size[j] == n - cut[k - 1 - dp_down[j]]);
prev_down[i] = size[j] == n - cut[k - 1 - dp_down[j]] ? id : prev_down[j];
}
continue;
}
assert((int)seq.size() == k + 1);
h.set_ignoration_rule([&](int id){ return res_cut[id]; });
vector<int> res(n, -1);
for(auto i = 0; i < (int)seq.size(); ++ i){
int u = seq[i];
df.dfs(h, {u});
for(auto u: df.order){
for(auto v: comp[u]){
res[v] = cnt[i].first;
}
}
}
cout << "Yes\n";
ranges::copy(res, ostream_iterator<int>(cout, " "));
cout << "\n";
if(ranges::min(res) < 0){
cout.flush();
assert(false);
}
return 0;
}
}
cout << "No\n";
return 0;
};
int __tc_cnt;
cin >> __tc_cnt;
for(auto __tc_num = 0; __tc_num < __tc_cnt; ++ __tc_num){
__solve_tc(__tc_num);
}
return 0;
}
/*
*/
Details
Tip: Click on the bar to expand more detailed information
Test #1:
score: 100
Accepted
time: 0ms
memory: 3532kb
input:
5 5 4 1 2 2 3 3 4 4 5 1 2 3 4 5 5 4 1 2 1 3 1 4 1 5 1 2 3 4 5 5 4 1 2 1 3 1 4 1 5 1 2 2 2 3 5 6 1 2 1 2 2 3 3 4 4 5 3 5 1 2 1 2 1 2 2 1 2 1 2 1 2
output:
Yes 1 2 3 4 5 No Yes 2 1 3 2 2 Yes 2 2 1 1 1 No
result:
ok ok (5 test cases)
Test #2:
score: -100
Wrong Answer
time: 233ms
memory: 3872kb
input:
100000 4 3 4 2 1 3 2 1 2 1 3 2 5 7 2 5 5 3 2 3 5 1 4 3 2 4 4 3 1 3 1 1 2 3 2 2 1 2 3 1 1 1 4 7 3 4 1 4 2 3 4 3 4 2 3 1 4 3 2 3 3 2 4 6 2 4 3 1 1 2 1 2 2 3 4 2 1 1 3 3 4 7 3 2 4 2 1 2 3 4 3 2 2 4 3 4 2 1 1 1 5 5 3 2 1 5 4 5 4 3 2 1 1 2 2 3 2 3 5 2 3 1 3 3 1 3 1 2 1 3 2 3 2 3 2 1 2 1 1 2 1 1 2 3 2 1 1...
output:
Yes 2 2 1 3 No Yes 1 1 1 No No Yes 2 1 1 1 No No No No No No No Yes 1 1 1 1 1 Yes 1 3 1 1 1 Yes 1 1 1 Yes 1 2 Yes 1 1 1 1 1 Yes 1 2 No No Yes 1 1 1 Yes 1 1 No No Yes 2 2 2 2 2 No Yes 1 1 Yes 1 1 1 2 No No No Yes 1 1 No No No Yes 1 1 1 1 2 Yes 1 2 1 1 No No No No Yes 3 1 3 3 2 Yes 1...
result:
wrong answer ans finds an answer, but out doesn't (test case 9)