Submission #442623

#TimeUsernameProblemLanguageResultExecution timeMemory
442623Haruto810198Road Closures (APIO21_roads)C++17
100 / 100
786 ms69224 KiB
#include <bits/stdc++.h>

using namespace std;

#define int long long
#define double long double

#define FOR(i,l,r,d) for(int i=(l);i<=(r);i+=(d))
#define szof(x) ((int)(x).size())

#define vi vector<int>
#define pii pair<int,int>

#define F first
#define S second

#define pb push_back
#define eb emplace_back
#define mkp make_pair

const int INF = 2147483647;
const int LNF = 4e18;
const int MOD = 1000000007;
const int mod = 998244353;
const double eps = 1e-12;

//#pragma GCC optimize("Ofast")
//#pragma GCC optimize("unroll-loops")

const int MAX = 100010;

int n;
vector<pii> edge[MAX]; /// original tree
int deg[MAX]; /// degree of vertices

pii par[MAX]; /// parent and childs of vectices, on the original tree
vector<pii> ch[MAX];

vi induced[MAX]; /// vectices of each induced subgraph
pii par_induced[MAX]; /// parent and childs of vectices, on the induced subgraph
vector<pii> ch_induced[MAX];

int dep[MAX]; /// depth of vectices
vi ord; /// order of dp
int dp[MAX][2]; /// dp[vertex][is connnected to parent]

/// Treap
struct Treap{
    Treap *l, *r;
    int key, pri;
    int sz, sum;
    Treap(int _k): l(nullptr), r(nullptr), key(_k), pri(rand()), sz(1), sum(_k) {}
};

inline int get_sz(Treap *T){
    return (T != nullptr) ? T -> sz : 0;
}

inline int get_sum(Treap *T){
    return (T != nullptr) ? T -> sum : 0;
}

void pull(Treap *&T){
    if(T == nullptr) return;
    T -> sz = get_sz(T -> l) + get_sz(T -> r) + 1;
    T -> sum = get_sum(T -> l) + get_sum(T -> r) + T -> key;
}

Treap* Merge(Treap *a, Treap *b){
    if(a == nullptr) return b;
    if(b == nullptr) return a;
    if(a -> pri < b -> pri){
        a -> r = Merge(a -> r, b);
        pull(a);
        return a;
    }
    else{
        b -> l = Merge(a, b -> l);
        pull(b);
        return b;
    }
}

void Split_by_key(Treap *T, Treap *&a, Treap *&b, int k){
    if(T == nullptr){
        a = b = nullptr;
        return;
    }
    if(T -> key < k){
        a = T;
        Split_by_key(T->r, a->r, b, k);
        pull(a);
    }
    else{
        b = T;
        Split_by_key(T->l, a, b->l, k);
        pull(b);
    }
}

void Split_by_sz(Treap *T, Treap *&a, Treap *&b, int k){
    if(T == nullptr){
        a = b = nullptr;
        return;
    }
    if(get_sz(T -> l) + 1 <= k){
        a = T;
        Split_by_sz(T->r, a->r, b, k - get_sz(T -> l) - 1);
        pull(a);
    }
    else{
        b = T;
        Split_by_sz(T->l, a, b->l, k);
        pull(b);
    }
}

void Insert(Treap *&T, int val){
    Treap *a, *b;
    Split_by_key(T, a, b, val);
    T = Merge( Merge(a, new Treap(val)), b );
}

void Erase(Treap *&T, int val){
    Treap *a, *b, *c;
    Split_by_key(T, a, b, val);
    Split_by_sz(b, b, c, 1);
    T = Merge(a, c);
}

Treap* edge_cnt[MAX];

void edge_cnt_insert(int v, int val){
    Insert(edge_cnt[v], val);
}

void edge_cnt_erase(int v, int val){
    Erase(edge_cnt[v], val);
}

int edge_cnt_query(int v, int q){
    if(q > get_sz(edge_cnt[v])) return LNF;
    Treap *a, *b;
    Split_by_sz(edge_cnt[v], a, b, q);
    int ret = get_sum(a);
    edge_cnt[v] = Merge(a, b);
    return ret;
}

/// calculate dep[], par[], ch[]
void dfs(int v, pii pv, int cdep){

    par[v] = pv;
    dep[v] = cdep;

    for(pii e : edge[v]){
        int i = e.F;
        int w = e.S;
        if(i == pv.F) continue;
        ch[v].pb(e);
        dfs(i, mkp(v, w), cdep + 1);
    }

}

bool cmp_by_dep(int u, int v){
    return (dep[u] < dep[v]);
}

/// solve for induced subgraph k
int solve(int k){

    for(int v : induced[k]){
        par_induced[v] = mkp(v, 0);
        ch_induced[v].clear();
    }

    /// update edges in induced subgraph k
    for(int v : induced[k]){
        int u = par[v].F;
        int w = par[v].S;
        if(v!=u and deg[u]>k){
            par_induced[v] = mkp(u, w);
            ch_induced[u].eb(v, w);
            edge_cnt_erase(v, w);
            edge_cnt_erase(u, w);
        }
    }

    /// dp order
    ord = induced[k];
    sort(ord.begin(), ord.end(), cmp_by_dep);
    reverse(ord.begin(), ord.end());

    /// dp

    int ret = 0;

    for(int v : ord){

        int ori_cost = 0; /// original cost if don't pick any child
        int n_sum = 0, n_cnt = 0; /// sum, n. of negative cost child

        /// cost of picking each child
        vi cost_ch;
        for(pii e : ch_induced[v]){
            int i = e.F;
            int w = e.S;
            /// pick : dp[i][1] + w
            /// not pick : dp[i][0]
            cost_ch.pb(dp[i][1] + w - dp[i][0]);
            ori_cost += dp[i][0];
        }
        sort(cost_ch.begin(), cost_ch.end());

        for(int i : cost_ch){
            if(i >= 0) break;
            n_sum += i;
            n_cnt++;
        }

        /// dp[v][0]
        dp[v][0] = LNF;

        int pick = deg[v] - k; /// n. of edges must pick to close
        int cost_ch_sum = n_sum;

        FOR(pick_ch, 0, pick, 1){ /// n. of edges picked from child
            int pick_ext = pick - pick_ch; /// n. of edges picked from extra edges
            dp[v][0] = min(dp[v][0], ori_cost + cost_ch_sum + edge_cnt_query(v, pick_ext));
            if(pick_ch >= szof(cost_ch)) break;
            if(pick_ch >= n_cnt){
                cost_ch_sum += cost_ch[pick_ch];
            }
        }

        /// if v is a root in the induced graph :
        if(par_induced[v].F == v){
            ret += dp[v][0];
            continue;
        }

        /// dp[v][1]
        dp[v][1] = LNF;

        pick = deg[v] - k - 1;
        cost_ch_sum = n_sum;

        FOR(pick_ch, 0, pick, 1){ /// n. of edges picked from child
            int pick_ext = pick - pick_ch; /// n. of edges picked from extra edges
            dp[v][1] = min(dp[v][1], ori_cost + cost_ch_sum + edge_cnt_query(v, pick_ext));
            if(pick_ch >= szof(cost_ch)) break;
            if(pick_ch >= n_cnt){
                cost_ch_sum += cost_ch[pick_ch];
            }
        }

    }

    /// recover edge_cnt
    for(int v : induced[k]){
        int u = par[v].F;
        int w = par[v].S;
        if(v!=u and deg[u]>k){
            edge_cnt_insert(v, w);
            edge_cnt_insert(u, w);
        }
    }

    return ret;

}

vi minimum_closure_costs(signed N, vector<signed> U, vector<signed> V, vector<signed> W){

    int wsum = 0;

    /// input
    n = N;
    FOR(i, 0, n-2, 1){
        int u = U[i], v = V[i], w = W[i];
        edge[u].eb(v, w);
        edge[v].eb(u, w);
        deg[u]++;
        deg[v]++;
        edge_cnt_insert(u, w);
        edge_cnt_insert(v, w);
        wsum += w;
    }

    /// dfs
    dfs(0, mkp(0, 0), 0);

    /// induced subgraph
    FOR(i, 0, n-1, 1){
        FOR(j, 0, deg[i]-1, 1){
            induced[j].pb(i);
        }
    }

    /// solve for each induced subgraph
    vi res(n);
    res[0] = wsum;
    FOR(i, 1, n-1, 1){
        res[i] = solve(i);
    }

    return res;

}
#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...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...