Submission #1343399

#TimeUsernameProblemLanguageResultExecution timeMemory
1343399madamadam3Simurgh (IOI17_simurgh)C++20
51 / 100
3091 ms26124 KiB
#include "simurgh.h"
#include <bits/stdc++.h>

using namespace std;
using vi = vector<int>;
using vvi = vector<vi>;
#define cout cerr

struct DSU {
	int n; vector<int> par, sz, U, P;
	DSU(int n = 0) : n(n), par(n, -1), sz(n, 1) {}
	int find(int v) {return par[v] == -1 ? v :par[v] = find(par[v]);}
	void unite(int a, int b) {
		a =find(a); b = find(b);
		if (a != b) {
			if (sz[a] < sz[b]) swap(a, b);
			U.push_back(b); P.push_back(par[b]);
			par[b] = a; sz[a] += sz[b];
		}
	}
};

vvi G; vi X, Y;

int timer = 0;
vi tin, low, par, back;
vi is_bridge, is_articulation_point;
vvi bccs; vi estack, my_bcc;

void dfs(int u, int p) {
	par[u] = p;
    tin[u] = low[u] = timer++;
    int children = 0;

    for (auto e : G[u]) {
        if (e == p) continue;
        int v = X[e] == u ? Y[e] : X[e];

        if (tin[v] == -1) {
            estack.push_back(e);
            dfs(v, e);
            if (low[v] > tin[u]) {
                is_bridge[e] = 1;
            }
            if (low[v] >= tin[u]) {
                if (p != -1) is_articulation_point[u] = 1;
                vi cmp; while (!estack.empty() && estack.back() != e) cmp.push_back(estack.back()), estack.pop_back();
                if (!estack.empty()) cmp.push_back(e), estack.pop_back();
				for (auto e : cmp) my_bcc[e] = bccs.size();
                bccs.push_back(cmp);
            }
			if (low[v] < low[u]) back[u] = e, low[u] = low[v];
            children++;
        } else if (tin[v] < tin[u]) { // back edge
            estack.push_back(e);
			if (tin[v] < low[u]) back[u] = e, low[u] = tin[v];
        }
    }

    if (p == -1 && children > 1) is_articulation_point[u] = 1;
}

int other_end(int e, int u) {
    return X[e] == u ? Y[e] : X[e];
}

bool is_tree_edge(int e) {
    return par[X[e]] == e || par[Y[e]] == e;
}

vi find_cycle(int e) {
    if (!is_tree_edge(e)) {
        int a = X[e], b = Y[e];
        int anc = tin[a] < tin[b] ? a : b;
        int desc = anc == a ? b : a;

        vi cyc = {e};
        int cur = desc;
        while (cur != anc) {
            int pe = par[cur];
            cyc.push_back(pe);
            cur = other_end(pe, cur);
        }
        return cyc;
    }

    int c = (par[X[e]] == e ? X[e] : Y[e]);
    int p = other_end(e, c);

    vi down;
    int cur = c;

    while (true) {
        int be = back[cur];
        if (is_tree_edge(be)) {
            int nxt = (par[X[be]] == be ? X[be] : Y[be]);
            down.push_back(be);
            cur = nxt;
        } else {
            int z = cur;
            int a = (tin[X[be]] < tin[Y[be]] ? X[be] : Y[be]);
            vi up;
            int x = p;
            while (x != a) {
                int pe = par[x];
                up.push_back(pe);
                x = other_end(pe, x);
            }
            reverse(up.begin(), up.end());

            vi cyc;
            cyc.push_back(e);
            for (int x : down) cyc.push_back(x);  
            cyc.push_back(be);
            for (int x : up) cyc.push_back(x); 

            return cyc;
        }
    }
}

vi find_roads(int n, vi u, vi v) {
	int m = u.size();
	X = u; Y = v; 
	map<pair<int, int>, int> rebase;
	G.assign(n, vi()); for (int i = 0; i < m; i++) G[u[i]].push_back(i), G[v[i]].push_back(i), rebase[{u[i], v[i]}] = i, rebase[{v[i], u[i]}] = i;
	deque<int> edges; tin.assign(n, -1), low.assign(n, -1); is_bridge.assign(m, 0); is_articulation_point.assign(n, 0);
	my_bcc.assign(m, -1); par.assign(n, -1); back.assign(n, -1);
	dfs(0, -1);

	for (int i = 0; i < m; i++) if (is_bridge[i]) edges.push_back(i);

	int bcc_cnt = bccs.size();
	vector<int> processed(bcc_cnt, 0);

	vi checked_royal(m, 0), royalc(m, 0);
	cout << "hi\n";
	auto is_royal = [&](int e) {
		if (is_bridge[e]) return royalc[e] = 1;
		if (checked_royal[e]) return royalc[e];

		auto dsu = DSU(n);
		vi pe = find_cycle(e); for (auto e : pe) dsu.unite(u[e], v[e]);

		vi cc; for (int i = 0; i < m; i++) {
			if (dsu.find(u[i]) != dsu.find(v[i])) dsu.unite(u[i], v[i]), cc.push_back(i);
		}

		vi R(pe.size(), -1);
		int found = -1;
		for (int i = 0; i < pe.size(); i++) {
			if (checked_royal[pe[i]]) found = i;
		}

		if (found == -1) {
			for (int i = 0; i < pe.size(); i++) {
				vi c = cc; for (int j = 0; j < pe.size(); j++) if (i != j) c.push_back(pe[j]);
				R[i] = count_common_roads(c);
			}

			int lo = *min_element(R.begin(), R.end()), hi = *max_element(R.begin(), R.end());
			cout << "the cycle of edge " << e << " was"; for (auto e : pe) cout << " " << e; cout << "\n";
			for (int i = 0; i < pe.size(); i++) {
				royalc[pe[i]] = R[i] != hi;
				checked_royal[pe[i]] = 1;
			}
		} else {
			vi c = cc; for (int j = 0; j < pe.size(); j++) if (found != j) c.push_back(pe[j]);
			int x1 = count_common_roads(c);
			vi c2 = cc; for (int j = 1; j < pe.size(); j++) c2.push_back(pe[j]);
			int x2 = count_common_roads(c2);
			if (x1 == x2) royalc[e] = royalc[pe[found]];
			else royalc[e] = x2 < x1;
		}
		checked_royal[e] = 1;
		return royalc[e];
	};

	vi mc, ans, royal(n-1, 0); // hammer
	set<int> used;
	auto dsu = DSU(n);
	for (int i = 0; i < m; i++) {
		if (dsu.find(u[i]) == dsu.find(v[i])) continue;
		dsu.unite(u[i], v[i]); mc.push_back(i);
		royal[mc.size()-1] = is_royal(i);
		if (royal[mc.size()-1]) ans.push_back(i);
		used.insert(i);
	}

	cout << "chosen: "; for (auto e : mc) cout << e << " "; cout << "\n";
	cout << "royal chosen: "; for (int i = 0; i < n-1; i++) if (royal[i]) cout << mc[i] << " "; cout << "\n";

	for (int i = 0; i < n; i++) {
		bool found = true;
		while (found) {
			found = false;
			int lo = 1, hi = G[i].size()+1;
			while (lo < hi) {
				int mid = lo + (hi-lo)/2;
				auto dsu2 = DSU(n);
				int exp = 0;
				vi cc; for (int j = 0; j < mid; j++) cc.push_back(G[i][j]), dsu2.unite(u[G[i][j]], v[G[i][j]]), exp += royalc[G[i][j]];
				for (int j = 0; j < n-1; j++) {
					if (dsu2.find(u[mc[j]]) == dsu2.find(v[mc[j]])) continue;
					exp += royal[j]; cc.push_back(mc[j]); dsu2.unite(u[mc[j]], v[mc[j]]);
				}

				int v = count_common_roads(cc);
				cout << "testing the set "; for (auto e : cc) cout << e << " "; cout << "expecting " << exp << " got " << v << "\n";
				if (v == exp) lo = mid + 1;
				else hi = mid, found = true;
			}
			
			if (found) {
				cout << "hallo\n";
				int e = G[i][lo-1];
				royalc[G[i][lo-1]] = 1;
				ans.push_back(e);
			}
		}
	}

	ans.clear(); for (int i =0 ; i < m; i++) if (royalc[i])ans.push_back(i);
	for (auto e : ans) cout << e << " "; cout << "\n";
	return ans;
}
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...