Submission #552769

#TimeUsernameProblemLanguageResultExecution timeMemory
552769QwertyPiRoad Closures (APIO21_roads)C++14
100 / 100
368 ms53580 KiB
#include "roads.h"

#include <bits/stdc++.h>
#define int long long
using namespace std;
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
vector<vector<pair<int, int>>> G(100000);
vector<vector<int>> H(100000);

int w[100000], par[100000], dep[100000];
void dfs_build(int v, int p = -1, int depth = 0){
	dep[v] = depth;
	for(auto i : G[v]){
		if(i.first != p){
			dfs_build(i.first, v, depth + 1);
			w[i.first] = i.second;
			par[i.first] = v;
		}
	}
}

int dp[100000][2];
int n;

vector<long long> had;
bool isHeavy[100000];
vector<pair<int, int>> deg;

// vector<vector<int>> store(100001);

bool visited[100000];

int d(int v, int u){
	if(v == -1 || u == -1) return (1LL << 60);
	return (dep[v] > dep[u]) ? w[v] : w[u];
}

struct item {
    int key, prior, cnt = 0, sum = 0;
    item * l, * r;
    item() { }
    item (int key, int prior) : key(key), prior(prior), cnt(1), sum(key), l(nullptr), r(nullptr) { }
};

typedef item * pitem;

int cnt (pitem t) {
    return t ? t->cnt : 0;
}

int sum (pitem t){
	return t ? t->sum : 0;
}

void upd_cnt (pitem t) {
    if (t) t->cnt = 1 + cnt(t->l) + cnt(t->r);
}

void upd_sum (pitem t) {
    if (t) t->sum = t->key + sum(t->l) + sum(t->r);
}

void split (pitem t, int key, pitem & l, pitem & r) {
    if (!t)
        l = r = NULL;
    else if (key < t->key)
        split (t->l, key, l, t->l),  r = t;
    else
        split (t->r, key, t->r, r),  l = t;
    upd_cnt(t);
    upd_sum(t);
}

void insert (pitem & t, pitem it) {
    if (!t)
        t = it;
    else if (it->prior > t->prior)
        split (t, it->key, it->l, it->r),  t = it;
    else
        insert (it->key < t->key ? t->l : t->r, it);
    upd_cnt(t);
    upd_sum(t);
}

void merge (pitem & t, pitem l, pitem r) {
    if (!l || !r)
        t = l ? l : r;
    else if (l->prior > r->prior)
        merge (l->r, l->r, r),  t = l;
    else
        merge (r->l, l, r->l),  t = r;
    upd_cnt(t);
    upd_sum(t);
}

void erase (pitem & t, int key) {
    if (t->key == key) {
        pitem th = t;
        merge (t, t->l, t->r);
        delete th;
    }
    else
        erase (key < t->key ? t->l : t->r, key);
    upd_cnt(t);
    upd_sum(t);
}

pitem unite (pitem l, pitem r) {
    if (!l || !r)  return l ? l : r;
    if (l->prior < r->prior)  swap (l, r);
    pitem lt, rt;
    split (r, l->key, lt, rt);
    l->l = unite (l->l, lt);
    l->r = unite (l->r, rt);
    return l;
}

int query(pitem & t, int k){
	if(!t || k == 0) return 0;
	if(cnt(t) == k) return t->sum;
	int res = 0;
	if(k <= cnt(t->l)) return query(t->l, k);
	if(cnt(t->l) + 1 <= k){
		res += sum(t->l);
		res += t->key;
		res += query(t->r, k - (cnt(t->l) + 1));
	}
	return res;
}

pitem store[100001];

void dfs(int v, int p = -1, int k = -1){
	visited[v] = true;
	vector<int> val;
	int ans = 0;
	int cnt = 0;
	
	for(auto i : H[v]){
		if(i != p){
			dfs(i, v, k);
			if(dp[i][0] <= dp[i][1]){
				ans += dp[i][0];
				cnt++;
				continue;
			}else{
				ans += dp[i][1];
				val.push_back(dp[i][0] - dp[i][1]);
			}
			
		}
	}
	
	for(auto i : val){
		pitem pi = new item(i, rng());
		insert(store[v], pi);
	}
	{
		int res = ans, to_del = max(0LL, (int) (G[v].size() - 1) - (k - 1) - cnt + 1);
		res += query(store[v], to_del);
		dp[v][1] = res;
	}
	{
		int res = ans + d(v, p), to_del = max(0LL, (int) (G[v].size() - 1) - (k) - cnt + 1);
		res += query(store[v], to_del);
		dp[v][0] = res;
	}
	for(auto i : val){
		erase(store[v], i);
	}
}

void migrate(int u, int v){ // u to v
	int weight = (dep[u] > dep[v] ? w[u] : w[v]);
	pitem pi = new item(weight, rng());
	insert(store[u], pi);
}

set<pair<int, int>> E;

void del_e(int u, int v){
	if(u > v) swap(u, v);
	E.erase({u, v});
}

void del(int v){
	for(auto i : G[v]){
		if(isHeavy[i.first]){
			migrate(i.first, v);
			del_e(i.first, v);
		}
	}
}

vector<long long> minimum_closure_costs(int32_t N, vector<int32_t> U, vector<int32_t> V, vector<int32_t> W) {
	for(int i = 0; i < N; i++){
		store[i] = new item(0, rng());
	}
	n = N;
	had.resize(N);
	for(int i = 0; i < N - 1; i++){
		if(U[i] > V[i]) swap(U[i], V[i]);
		G[U[i]].push_back({V[i], W[i]});
		G[V[i]].push_back({U[i], W[i]});
		E.insert({U[i], V[i]});
	}
	for(int i = 0; i < N; i++){
		deg.push_back({G[i].size(), i});
	}
	sort(deg.begin(), deg.end());
	int idx = 0;
	dfs_build(0);
	w[0] = (1LL << 60);
	fill(isHeavy, isHeavy + N, 1);
	for(int k = 0; k < N; k++){
		while(idx < N && deg[idx].first <= k){
			del(deg[idx].second);
			isHeavy[deg[idx].second] = false;
			idx++;
		}
		
		for(int i = idx; i < N; i++) visited[deg[i].second] = false;
		for(int i = idx; i < N; i++){
			H[deg[i].second].clear();
		}
		for(auto i : E){
			H[i.first].push_back(i.second);
			H[i.second].push_back(i.first);
		}
		for(int i = idx; i < N; i++){
			int v = deg[i].second;
			if(!visited[v]){
				dfs(v, -1, k);
				had[k] += min(dp[v][0], dp[v][1]);
			}
		}
//		cout << "FOR " << k << ": " << endl; 
//		for(int i = 0; i < n; i++){
//			cout << dp[i][0] << ' ' << dp[i][1] << endl;
//		}
	}
	return had;
}
#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...