This documentation is automatically generated by online-judge-tools/verification-helper
#include "Graph/opttoposort.hpp"
#pragma once #include "DataStructure/unionfind.hpp" // root:0, minimize sum_{i<j} w1[q_i]*w0[q_j] ll OptimalToposort(int n, vector<int> &p, vector<ll> &w0, vector<ll> &w1) { struct Node { ll zero, one, inv; Node(ll z = 0, ll o = 0, ll i = 0) : zero(z), one(o), inv(i) {} bool operator<(const Node &other) const { return zero * other.one < one * other.zero; } bool operator!=(const Node &other) const { return zero != other.zero or one != other.one; } }; using P = pair<Node, int>; priority_queue<P> pq; UnionFind uni(n); vector<Node> info(n); rep(i, 0, n) { info[i] = Node{w0[i], w1[i], 0}; if (i) pq.push({info[i], i}); } vector<int> head(n); iota(ALL(head), 0); while (!pq.empty()) { auto [pre, x] = pq.top(); pq.pop(); if (uni.root(x) != x or pre != info[x]) continue; int par = p[head[x]]; assert(par != -1); par = uni.root(par); uni.unite(x, par); int nxt = uni.root(x); head[nxt] = head[par]; Node X = info[par], Y = info[x]; Node cur = {X.zero + Y.zero, X.one + Y.one, X.inv + Y.inv + X.one * Y.zero}; info[nxt] = cur; if (uni.root(0) != nxt) { pq.push({info[nxt], nxt}); } } return info[uni.root(0)].inv; }; /** * @brief Optimal Topological sort */
#line 2 "DataStructure/unionfind.hpp" struct UnionFind{ vector<int> par; int n; UnionFind(){} UnionFind(int _n):par(_n,-1),n(_n){} int root(int x){return par[x]<0?x:par[x]=root(par[x]);} bool same(int x,int y){return root(x)==root(y);} int size(int x){return -par[root(x)];} bool unite(int x,int y){ x=root(x),y=root(y); if(x==y)return false; if(size(x)>size(y))swap(x,y); par[y]+=par[x]; par[x]=y; n--; return true; } }; /** * @brief Union Find */ #line 3 "Graph/opttoposort.hpp" // root:0, minimize sum_{i<j} w1[q_i]*w0[q_j] ll OptimalToposort(int n, vector<int> &p, vector<ll> &w0, vector<ll> &w1) { struct Node { ll zero, one, inv; Node(ll z = 0, ll o = 0, ll i = 0) : zero(z), one(o), inv(i) {} bool operator<(const Node &other) const { return zero * other.one < one * other.zero; } bool operator!=(const Node &other) const { return zero != other.zero or one != other.one; } }; using P = pair<Node, int>; priority_queue<P> pq; UnionFind uni(n); vector<Node> info(n); rep(i, 0, n) { info[i] = Node{w0[i], w1[i], 0}; if (i) pq.push({info[i], i}); } vector<int> head(n); iota(ALL(head), 0); while (!pq.empty()) { auto [pre, x] = pq.top(); pq.pop(); if (uni.root(x) != x or pre != info[x]) continue; int par = p[head[x]]; assert(par != -1); par = uni.root(par); uni.unite(x, par); int nxt = uni.root(x); head[nxt] = head[par]; Node X = info[par], Y = info[x]; Node cur = {X.zero + Y.zero, X.one + Y.one, X.inv + Y.inv + X.one * Y.zero}; info[nxt] = cur; if (uni.root(0) != nxt) { pq.push({info[nxt], nxt}); } } return info[uni.root(0)].inv; }; /** * @brief Optimal Topological sort */