E - Easy Compare-and-Set
题意
给定n个条件,如果存在一个合法序列使得这n个判断条件成立,则输出Yes和这个合法序列,否则输出No。
分析
首先可以发现对于\(w_i = 0\)的操作我们可以在处理完\(w_i = 1\)的操作之后讨论一下即可。
发现\(a_i\)和\(b_i\)很大需要对其进行离散化操作。离散化后可以将\(a_i\)和\(b_i\)看成点,即一条从a走向b的有向边。将所有的\(w_i = 1\)的边连接起来之后,则可以发现题目等价于问以c为起点能否恰好经过每条边一次,最后跑一边欧拉回路记录路径即可。
对于\(w_i = 0\)的情况我们可以先将所有\(a_i \neq c\)的操作先用掉,对于\(a_i = c\)的操作在跑图时插在第2的点中间即可。
最后注意判断无解情况,具体看代码实现。
代码实现
#include <bits/stdc++.h>
int main() {
std::cin.tie(nullptr)->sync_with_stdio(false);
int n, c;
std::cin >> n >> c;
std::unordered_map<int, int> mp;
std::vector<int> w(n);
std::vector<std::array<int, 3>> edges(n);
int cur = 0;
mp[c] = cur++;
c = mp[c];
for (int i = 0; i < n; ++i) {
int a, b;
std::cin >> a >> b >> w[i];
if (!mp.count(a)) mp[a] = cur++;
if (!mp.count(b)) mp[b] = cur++;
a = mp[a], b = mp[b];
edges[i] = {a, b, w[i]};
}
std::vector<int> din(cur), dout(cur);
std::vector<std::vector<std::pair<int, int>>> g(cur);
std::set<int> dot;
for (int i = 0; i < n; ++i) {
auto [a, b, e] = edges[i];
if (e == 1) {
g[a].emplace_back(b, i);
dot.emplace(a), dot.emplace(b);
din[b] += 1, dout[a] += 1;
}
}
for (int num = 0; auto x : dot) if (din[x] != dout[x]) {
if (din[x] < dout[x]) {
if (x != c || dout[x] - din[x] > 1) {
std::cout << "No" << '\n';
return 0;
}
} else {
num += 1;
if (num > 1 || din[x] - dout[x] > 1) {
std::cout << "No" << '\n';
return 0;
}
}
}
std::vector<bool> use(n);
std::vector<int> path, ans1, ans2;
for (int i = 0; i < n; ++i) {
auto [a, b, _] = edges[i];
if (w[i] == 0 && a != c) {
use[i] = true;
ans1.emplace_back(i);
} else if (w[i] == 0) {
use[i] = true;
ans2.emplace_back(i);
}
}
auto dfs = [&](auto &&self, int u) ->void {
while(size(g[u])) {
auto [v, e] = g[u].rbegin()[0];
use[e] = true;
g[u].pop_back();
self(self, v);
path.emplace_back(e);
}
};
dfs(dfs, c);
if (((int)size(path) == 0 && size(ans2)) || std::count(use.begin(), use.end(), true) != n || (cur == 1 && std::count(w.begin(), w.end(), 1) != n)) {
std::cout << "No" << '\n';
} else {
std::cout << "Yes" << '\n';
for (int i = 0; i < (int)size(ans1); ++i) {
std::cout << ans1[i] + 1 << " ";
}
int pos = size(path);
for (int i = 0; i < (int)size(path); ++i) {
if (edges[path.rbegin()[i]][0] == c) {
std::cout << path.rbegin()[i] + 1 << " \n"[i == (int)size(path) - 1];
} else {
pos = i;
break;
}
}
for (int i = 0; i < (int)size(ans2); ++i) {
std::cout << ans2[i] + 1 << " ";
}
for (int i = pos; i < (int)size(path); ++i) {
std::cout << path.rbegin()[i] + 1 << " \n"[i == (int)size(path) - 1];
}
}
}
Thanks:
标签:std,din,North,cur,Northern,Contest,int,auto,mp From: https://www.cnblogs.com/sleeeeeping/p/18167933最后感谢学弟提供的hack样例,不然实在是没想到为什么wa6。
╲(。◕‿◕。)╱