제출 #725102

#제출 시각아이디문제언어결과실행 시간메모리
725102faremy도로 폐쇄 (APIO21_roads)C++14
100 / 100
430 ms44004 KiB
#include <iostream>
#include <random>

using uint = unsigned int;
using ll = long long;
using ull = unsigned long long;

//Wrapper for generating random integers from [0, N[
class RandInt
{
        static std::random_device rd;
        static std::mt19937 gen;
        std::uniform_int_distribution<ll> distrib;

public:
        RandInt(ll N) : distrib(0, N - 1) {}
        ll operator ()() { return distrib(gen); }
};

std::random_device RandInt::rd;
std::mt19937 RandInt::gen(rd());

//End of template

#include "roads.h"

#include <vector>
#include <utility>
#include <unordered_map>
#include <queue>
#include <algorithm>

//Treap
struct TreapNode
{
	TreapNode(ll v) : value(v), priority(gen_prio()), sum(v) {}
	~TreapNode() { delete left; delete right; }

	ll value, priority;
	int size = 1;
	ll sum;
	TreapNode *left = nullptr, *right = nullptr;

private:
	static RandInt gen_prio;
};

const ll INFTY = 1LL << 62;
RandInt TreapNode::gen_prio(INFTY);

using Treap = TreapNode *;
using Treapair = std::pair<Treap, Treap>;

int size(Treap t)
{
	if (t)
		return t->size;
	return 0;
}

ll sum(Treap t)
{
	if (t)
		return t->sum;
	return 0;
}

Treapair cut(Treap t, ll v)
{
	if (t == nullptr)
		return { nullptr, nullptr };
	if (t->value < v)
	{
		Treapair sub = cut(t->right, v);
		t->right = sub.first;
		t->size -= size(sub.second);
		t->sum -= sum(sub.second);
		return { t, sub.second };
	}
	else
	{
		Treapair sub = cut(t->left, v);
		t->left = sub.second;
		t->size -= size(sub.first);
		t->sum -= sum(sub.first);
		return { sub.first, t };
	}
}

Treap merge(Treap l, Treap r)
{
	if (l == nullptr)
		return r;
	if (r == nullptr)
		return l;
	if (l->priority > r->priority)
	{
		l->size += size(r);
		l->sum += sum(r);
		l->right = merge(l->right, r);
		return l;
	}
	else
	{
		r->size += size(l);
		r->sum += sum(l);
		r->left = merge(l, r->left);
		return r;
	}
}

void insert(Treap &t, ll v)
{
	Treapair split = cut(t, v);
	t = merge(merge(split.first, new TreapNode(v)), split.second);
}

int cnt_range(Treap &t, ll a, ll b)
{
	Treapair low = cut(t, a);
	Treapair high = cut(low.second, b);
	int res = size(high.first);
	t = merge(low.first, merge(high.first, high.second));
	return res;
}

ll sum_k(Treap &t, int k)
{
	if (k <= 0)
		return 0;
	if (t == nullptr)
		return INFTY;
	
	if (k > size(t->left))
		return sum(t->left) + t->value + sum_k(t->right, k - size(t->left) - 1);
	return sum_k(t->left, k);
}

ll sum_k_range(Treap &t, ll a, ll b, int k)
{
	Treapair low = cut(t, a);
	Treapair high = cut(low.second, b);
	ll res = sum_k(high.first, k);
	t = merge(low.first, merge(high.first, high.second));
	return res;
}

//Main code
const int MAXN = 1e5;

std::unordered_map<int, ll> tree[MAXN];
Treap dead_neighbors[MAXN];
int degree[MAXN];
int deg_order[MAXN];

bool seen[MAXN];
ll min_cuts[MAXN][2];

ll cut_children(int node, int parent, int maxdeg)
{
	int remain = degree[node] - maxdeg;
	std::priority_queue<ll> add_cost;
	ll res = 0;

	for (auto [child, _] : tree[node])
	{
		if (child != parent)
		{
			if (min_cuts[child][1] > min_cuts[child][0])
			{
				res += min_cuts[child][0];
				add_cost.emplace(min_cuts[child][0] - min_cuts[child][1]);
			}
			else
			{
				res += min_cuts[child][1];
				remain--;
			}
		}
	}

	ll previous_alive = 0;
	while (remain > 0 && !add_cost.empty())
	{
		ll smallest_alive = -add_cost.top();
		add_cost.pop();

		int cnt_dead = cnt_range(dead_neighbors[node], previous_alive, smallest_alive);
		if (cnt_dead < remain)
		{
			res += sum_k_range(dead_neighbors[node], previous_alive, smallest_alive, cnt_dead) + smallest_alive;
			remain -= cnt_dead + 1;
		}
		else
		{
			res += sum_k_range(dead_neighbors[node], previous_alive, smallest_alive, remain);
			remain = 0;
		}

		previous_alive = smallest_alive;
	}

	res += sum_k_range(dead_neighbors[node], previous_alive, INFTY, remain);
	return res;
}

void compute_cuts(int node, int parent, int maxdeg)
{
	seen[node] = true;
	for (auto [child, _] : tree[node])
		if (child != parent)
			compute_cuts(child, node, maxdeg);

	min_cuts[node][0] = cut_children(node, parent, maxdeg);
	if (parent != -1)
		min_cuts[node][1] = cut_children(node, parent, maxdeg + 1) + tree[node][parent];
}

std::vector<ll> minimum_closure_costs(int N, std::vector<int> U, std::vector<int> V, std::vector<int> W)
{
	for (int iEdge = 0; iEdge < N - 1; iEdge++)
	{
		tree[U[iEdge]][V[iEdge]] = W[iEdge];
		tree[V[iEdge]][U[iEdge]] = W[iEdge];
	}
	
	for (int iNode = 0; iNode < N; iNode++)
	{
		dead_neighbors[iNode] = nullptr;
		degree[iNode] = tree[iNode].size();
		deg_order[iNode] = iNode;
		seen[iNode] = false;
	}

	std::sort(deg_order, deg_order + N, [](int u, int v) { return degree[u] < degree[v]; });
	int first_alive = 0;

	std::vector<ll> ans(N, 0);
	for (int maxdeg = 0; maxdeg < N; maxdeg++)
	{
		while (first_alive < N && degree[deg_order[first_alive]] <= maxdeg)
		{
			for (auto [neighbor, weight] : tree[deg_order[first_alive]])
			{
				tree[neighbor].erase(tree[neighbor].find(deg_order[first_alive]));
				insert(dead_neighbors[neighbor], weight);
			}
			first_alive++;
		}

		for (int iNode = first_alive; iNode < N; iNode++)
			if (!seen[deg_order[iNode]])
			{
				compute_cuts(deg_order[iNode], -1, maxdeg);
				ans[maxdeg] += min_cuts[deg_order[iNode]][0];
			}

		for (int iNode = first_alive; iNode < N; iNode++)
			seen[deg_order[iNode]] = false;
	}

	for (int iNode = 0; iNode < N; iNode++)
		delete dead_neighbors[iNode];
	return ans;
}

컴파일 시 표준 에러 (stderr) 메시지

roads.cpp: In function 'll cut_children(int, int, int)':
roads.cpp:165:12: warning: structured bindings only available with '-std=c++17' or '-std=gnu++17'
  165 |  for (auto [child, _] : tree[node])
      |            ^
roads.cpp: In function 'void compute_cuts(int, int, int)':
roads.cpp:210:12: warning: structured bindings only available with '-std=c++17' or '-std=gnu++17'
  210 |  for (auto [child, _] : tree[node])
      |            ^
roads.cpp: In function 'std::vector<long long int> minimum_closure_costs(int, std::vector<int>, std::vector<int>, std::vector<int>)':
roads.cpp:243:14: warning: structured bindings only available with '-std=c++17' or '-std=gnu++17'
  243 |    for (auto [neighbor, weight] : tree[deg_order[first_alive]])
      |              ^
#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...