Submission #969083

#TimeUsernameProblemLanguageResultExecution timeMemory
969083GrindMachineSimurgh (IOI17_simurgh)C++17
32 / 100
154 ms6176 KiB
#include <bits/stdc++.h> #include <ext/pb_ds/assoc_container.hpp> #include <ext/pb_ds/tree_policy.hpp> using namespace std; using namespace __gnu_pbds; template<typename T> using Tree = tree<T, null_type, less<T>, rb_tree_tag, tree_order_statistics_node_update>; typedef long long int ll; typedef long double ld; typedef pair<int,int> pii; typedef pair<ll,ll> pll; #define fastio ios_base::sync_with_stdio(false); cin.tie(NULL) #define pb push_back #define endl '\n' #define sz(a) (int)a.size() #define setbits(x) __builtin_popcountll(x) #define ff first #define ss second #define conts continue #define ceil2(x,y) ((x+y-1)/(y)) #define all(a) a.begin(), a.end() #define rall(a) a.rbegin(), a.rend() #define yes cout << "Yes" << endl #define no cout << "No" << endl #define rep(i,n) for(int i = 0; i < n; ++i) #define rep1(i,n) for(int i = 1; i <= n; ++i) #define rev(i,s,e) for(int i = s; i >= e; --i) #define trav(i,a) for(auto &i : a) template<typename T> void amin(T &a, T b) { a = min(a,b); } template<typename T> void amax(T &a, T b) { a = max(a,b); } #ifdef LOCAL #include "debug.h" #else #define debug(x) 42 #endif /* refs: https://codeforces.com/blog/entry/53595?#comment-376568 */ const int MOD = 1e9 + 7; const int N = 500 + 5; const int inf1 = int(1e9) + 5; const ll inf2 = ll(1e18) + 5; #include "simurgh.h" struct DSU { vector<int> par, rankk, siz; DSU() { } DSU(int n) { init(n); } void init(int n) { par = vector<int>(n + 1); rankk = vector<int>(n + 1); siz = vector<int>(n + 1); rep(i, n + 1) create(i); } void create(int u) { par[u] = u; rankk[u] = 0; siz[u] = 1; } int find(int u) { if (u == par[u]) return u; else return par[u] = find(par[u]); } bool same(int u, int v) { return find(u) == find(v); } void merge(int u, int v) { u = find(u), v = find(v); if (u == v) return; if (rankk[u] == rankk[v]) rankk[u]++; if (rankk[u] < rankk[v]) swap(u, v); par[v] = u; siz[u] += siz[v]; } }; int f(vector<int> v){ return count_common_roads(v); } vector<pii> adj[N]; vector<int> ord; vector<int> tin(N); vector<pii> low(N); vector<bool> vis(N); int timer = 1; vector<int> spanning; vector<pii> par(N); void dfs1(int u, int p){ vis[u] = 1; tin[u] = timer++; low[u] = {tin[u],-1}; for(auto [v,id] : adj[u]){ if(v == p) conts; if(vis[v]){ amin(low[u],{tin[v],id}); } else{ spanning.pb(id); par[v] = {u,id}; dfs1(v,u); amin(low[u],low[v]); } } ord.pb(u); } std::vector<int> find_roads(int n, std::vector<int> U, std::vector<int> V) { int m = sz(U); rep(i,m){ int u = U[i], v = V[i]; adj[u].pb({v,i}), adj[v].pb({u,i}); } dfs1(0,-1); vector<int> status(m,-1); int original = f(spanning); trav(u,ord){ // find the val of the incoming span edge if(!u) conts; auto [p,pid] = par[u]; if(low[u].ff > tin[p]){ status[pid] = 1; conts; } int cyc_id = low[u].ss; int x = U[cyc_id], y = V[cyc_id]; if(tin[x] < tin[y]) swap(x,y); vector<int> pending; while(x != y){ auto [p,pid] = par[x]; if(status[pid] != -1){ auto curr = spanning; curr.erase(find(all(curr),pid)); curr.pb(cyc_id); int val = f(curr); int cyc_status = val+status[pid]-original; while(!pending.empty()){ int edge_id = pending.back(); pending.pop_back(); curr = spanning; curr.erase(find(all(curr),edge_id)); curr.pb(cyc_id); val = f(curr); status[edge_id] = original+cyc_status-val; } break; } x = p; pending.pb(pid); } if(pending.empty()) conts; // full cycle, none known pending.pb(cyc_id); auto curr = spanning; curr.pb(cyc_id); map<int,vector<int>> mp; trav(id,pending){ curr.erase(find(all(curr),id)); int val_without = f(curr); curr.pb(id); mp[val_without].pb(id); } if(sz(mp) == 1){ // all 0 trav(id,pending){ status[id] = 0; } } else{ assert(sz(mp) == 2); trav(id,mp.begin()->second){ status[id] = 1; } trav(id,(--mp.end())->second){ status[id] = 0; } } } auto get = [&](vector<int> edges){ // edges form a star at some node u DSU dsu(n); trav(id,edges){ dsu.merge(U[id],V[id]); } auto curr = edges; int extra = 0; trav(id,spanning){ int u = U[id], v = V[id]; if(dsu.same(u,v)) conts; dsu.merge(u,v); extra += status[id]; curr.pb(id); } int val = f(curr); return val-extra; }; // find the status of all non-tree adj edges to u (s.t u < v) rep(u,n){ vector<int> edges; for(auto [v,id] : adj[u]){ if(status[id] != -1) conts; if(v < u) conts; edges.pb(id); } while(!edges.empty()){ if(!get(edges)) break; int l = 0, r = sz(edges)-1; int first = -1; while(l <= r){ int mid = (l+r) >> 1; vector<int> curr_edges; rep(i,mid+1) curr_edges.pb(edges[i]); if(get(curr_edges)){ first = mid; r = mid-1; } else{ l = mid+1; } } assert(first != -1); vector<int> nxt_edges; rep(i,sz(edges)){ if(i < first){ status[edges[i]] = 0; } else if(i == first){ status[edges[i]] = 1; } else{ nxt_edges.pb(edges[i]); } } edges = nxt_edges; } } vector<int> ans; rep(i,m){ if(status[i] == 1){ ans.pb(i); } } 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...