Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <bits/stdc++.h>
- using namespace std;
- typedef long double ld;
- typedef long long ll;
- typedef pair<double, double> pdd;
- typedef vector<double> vd;
- typedef vector<vd> vvd;
- typedef vector<ll> vl;
- typedef vector<vl> vvl;
- typedef pair<int, int> pii;
- typedef vector<pii> vii;
- typedef vector<int> vi;
- typedef vector<vi> vvi;
- typedef vector<string> vs;
- struct TEdge {
- int from, to;
- ll capacity, flow;
- TEdge* reverse;
- };
- TEdge edgePool[1000000];
- int edgePoolPtr = 0;
- typedef vector<TEdge*> ve;
- vector< ve > edges; //resize
- int col[1000000];
- int SOURCE, TARGET; //assign
- TEdge* AddEdge(int from, int to, ll capacity) {
- TEdge* e1 = &edgePool[edgePoolPtr++];
- TEdge* e2 = &edgePool[edgePoolPtr++];
- TEdge fw = {from, to, capacity, 0, e2};
- TEdge bw = {to, from, 0, 0, e1};
- *e1 = fw;
- *e2 = bw;
- edges[from].push_back(e1);
- edges[to].push_back(e2);
- return e1;
- }
- inline ll AvailableCapacity(const TEdge* p) {
- return (p->capacity - p->flow);
- }
- class TDinic {
- public:
- vector<int> Distances;
- vector<size_t> Ptr;
- int N;
- void BFS() {
- deque<int> q;
- Distances.assign(N, -1);
- Distances[SOURCE] = 0;
- q.push_back(SOURCE);
- while (!q.empty()) {
- int p = q.front();
- q.pop_front();
- for (size_t i = 0; i < edges[p].size(); i++) {
- if (!AvailableCapacity(edges[p][i]))
- continue;
- int c = edges[p][i]->to;
- if (Distances[c] == -1) {
- Distances[c] = Distances[p] + 1;
- q.push_back(c);
- }
- }
- }
- }
- ll DFS(int p, ll fl) {
- if (fl == 0)
- return 0;
- if (p == TARGET)
- return fl;
- ll res = 0;
- for (size_t &i = Ptr[p]; Ptr[p] < edges[p].size() && fl != 0; ++i) {
- if (!AvailableCapacity(edges[p][i])) {
- continue;
- }
- if (Distances[edges[p][i]->from] + 1 != Distances[edges[p][i]->to])
- continue;
- ll pushed = DFS(edges[p][i]->to, min(fl, AvailableCapacity(edges[p][i])));
- fl -= pushed;
- res += pushed;
- edges[p][i]->flow += pushed;
- edges[p][i]->reverse->flow -= pushed;
- if (fl == 0)
- break;
- }
- return res;
- }
- /*void init() {
- SOURCE,TARGET
- edges.clear();
- edgePoolPtr = 0;
- edges.resize();
- }*/
- ll calc_max_flow() {
- N = (int)edges.size();
- ll res = 0;
- while (true) {
- BFS();
- Ptr.assign(N, 0);
- ll p = DFS(SOURCE, LLONG_MAX / 2);
- if (!p)
- break;
- res += p;
- }
- return res;
- }
- };
- struct Graph {
- void read() {
- int m;
- cin >> n >> m;
- e.resize(n);
- for (int i = 0; i < m; ++i) {
- int u, v;
- cin >> u >> v;
- --u; --v;
- e[u].push_back(v);
- e[v].push_back(u);
- }
- }
- /* COMMON PART */
- int n;
- vector<vector<int>> e;
- int counter = 1;
- vector<int> inTime, minInTime;
- void dfs(int v, int p = -1) {
- minInTime[v] = inTime[v] = counter++;
- for (int u: e[v]) {
- if (u == p) continue;
- if (!inTime[u]) {
- dfs(u, v);
- minInTime[v] = min(minInTime[v], minInTime[u]);
- }
- else {
- minInTime[v] = min(minInTime[v], inTime[u]);
- }
- }
- }
- vector<char> used;
- /* COMPONENTS SEPARATED BY BRIDGES (COLORING) */
- int nColors;
- vector<int> color;
- void colorDfs(int v, int curColor) {
- color[v] = curColor;
- for (int u: e[v]) {
- if (color[u] != -1) continue;
- colorDfs(u, minInTime[u] > inTime[v] ? nColors++ : curColor);
- }
- }
- void findVertexComponents() {
- inTime.assign(n, 0);
- minInTime.assign(n, 0);
- counter = 1;
- for (int i = 0; i < n; ++i)
- if (!inTime[i])
- dfs(i);
- nColors = 0;
- color.assign(n, -1);
- for (int i = 0; i < n; ++i)
- if (color[i] == -1) {
- colorDfs(i, nColors++);
- }
- }
- /* COMPONENTS SEPARATED BY JOINTS (EDGE COMPONENTS) */
- struct Edge {
- int u, v;
- };
- // Cactus loops can be parsed as .u of every edge
- vector<vector<Edge>> edgeComps;
- vector<int> colorStack;
- void edgeCompDfs(int v, int p = -1) {
- used[v] = true;
- for (int u: e[v]) {
- if (used[u]) {
- if (inTime[u] < inTime[v] && u != p) {
- // NOTE: && u != p makes one-edge components contain exactly one edge;
- // if you need them as two-edge loops, remove this part of if condition
- edgeComps[colorStack.back()].push_back({v, u});
- }
- continue;
- }
- bool newComp = minInTime[u] >= inTime[v];
- if (newComp) {
- colorStack.push_back(edgeComps.size());
- edgeComps.emplace_back();
- }
- edgeComps[colorStack.back()].push_back({v, u});
- edgeCompDfs(u, v);
- if (newComp) {
- colorStack.pop_back();
- }
- }
- }
- void findEdgeComponents() {
- inTime.assign(n, 0);
- minInTime.assign(n, 0);
- counter = 1;
- for (int i = 0; i < n; ++i)
- if (!inTime[i])
- dfs(i);
- used.assign(n, false);
- colorStack.clear();
- edgeComps.clear();
- for (int i = 0; i < n; ++i)
- if (!used[i]) {
- assert(colorStack.empty());
- edgeCompDfs(i);
- }
- }
- };
- int main() {
- std::ios::sync_with_stdio(false); std::cin.tie(0);
- Graph g;
- g.read();
- for (int i = 0; i < g.n; ++i) {
- cin >> col[i];
- --col[i];
- }
- g.findEdgeComponents();
- for (auto v : g.edgeComps) if (v.size() > 1) {
- vi was(3, -1);
- for (auto e : v) {
- was[col[e.u]] = e.u;
- was[col[e.v]] = e.v;
- cerr << e.u+1 << ' ' << e.v+1 << '|';
- }
- cerr << endl;
- for (auto e : v) {
- if (col[e.u] != col[e.v]) {
- int remcol = 3 - col[e.u] - col[e.v];
- int root = was[remcol];
- if (root < 0) break;
- map<int, int> ind;
- vi invind;
- for (auto e1 : v) {
- for (int x : {e1.v, e1.u}) if (!ind.count(x)) {
- ind[x] = invind.size();
- invind.push_back(x);
- }
- }
- TDinic flow;
- edges.clear();
- edgePoolPtr = 0;
- SOURCE = 2 * ind[root] + 1, TARGET = 2 * ind[e.u] + 1;
- edges.resize(invind.size() * 2);
- for (auto e1 : v) {
- if (pii(e1.u, e1.v) != pii(e.u, e.v)) {
- AddEdge(2 * ind[e1.u] + 1, 2 * ind[e1.v], 1);
- AddEdge(2 * ind[e1.v] + 1, 2 * ind[e1.u], 1);
- }
- }
- for (int i = 0; i < invind.size(); ++i) {
- if (invind[i] != e.v) {
- AddEdge(2 * i, 2 * i + 1, 1);
- } else {
- AddEdge(2 * i, TARGET, 1);
- }
- }
- assert(flow.calc_max_flow() == 2);
- cout << "YES\n";
- vi res(1, root);
- for (auto ef : edges[SOURCE]) {
- if (ef->from == SOURCE && ef->flow) {
- vi path;
- int cur = ef->to;
- while (cur != TARGET) {
- if (cur % 2 == 0) path.push_back(cur);
- for (auto ef1 : edges[cur]) if (ef->from == cur && ef1->flow) {
- cur = ef1->to;
- break;
- }
- }
- if (!res.empty()) reverse(path.begin(), path.end());
- for (int x : path) res.push_back(invind[x]);
- }
- }
- cout << res.size() << endl;
- for (int x : res) cout << x + 1 << ' '; cout << endl;
- break;
- }
- }
- }
- cout << "NO\n";
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment