Submission #1155134

#TimeUsernameProblemLanguageResultExecution timeMemory
1155134fve5Truck Driver (IOI23_deliveries)C++20
100 / 100
1917 ms54728 KiB
#include <bits/stdc++.h>
#include "deliveries.h"
using namespace std;

struct Info {
	int64_t sum_t;
	int64_t sum_hi, sum_lo;

	void apply_lazy(pair<int64_t, int64_t> lazy) {
		sum_hi += lazy.first * sum_t;
		sum_lo += lazy.second * sum_t;
	}
};

Info merge(Info x, Info y) {
	return {x.sum_t + y.sum_t, x.sum_hi + y.sum_hi, x.sum_lo + y.sum_lo};
}

class SegTree {
	int s;
	vector<Info> arr;
	vector<pair<int64_t, int64_t>> lazy;

	void update(int nb, int ne, int n) {
		arr[n].apply_lazy(lazy[n]);
		if (nb + 1 != ne) {
			lazy[2 * n].first += lazy[n].first;
			lazy[2 * n].second += lazy[n].second;
			lazy[2 * n + 1].first += lazy[n].first;
			lazy[2 * n + 1].second += lazy[n].second;
		}
		lazy[n] = {0, 0};
	}

	void update(int l, int r, pair<int64_t, int64_t> upd, int nb, int ne, int n) {
		update(nb, ne, n);
		if (nb >= r || ne <= l) return;
		if (l <= nb && ne <= r) {
			lazy[n].first += upd.first;
			lazy[n].second += upd.second;
			update(nb, ne, n);
			return;
		}
		update(l, r, upd, nb, (nb + ne) / 2, 2 * n);
		update(l, r, upd, (nb + ne) / 2, ne, 2 * n + 1);

		arr[n] = merge(arr[2 * n], arr[2 * n + 1]);
	}

	pair<int64_t, int64_t> query(int l, int r, int nb, int ne, int n) {
		update(nb, ne, n);
		if (nb >= r || ne <= l) return {0, 0};
		if (l <= nb && ne <= r) return {arr[n].sum_hi, arr[n].sum_lo};

		auto [l_hi, l_lo] = query(l, r, nb, (nb + ne) / 2, 2 * n);
		auto [r_hi, r_lo] = query(l, r, (nb + ne) / 2, ne, 2 * n + 1);
		return {l_hi + r_hi, l_lo + r_lo};
	}

public:

	void update(int l, int r, pair<int64_t, int64_t> upd) {
		update(l, r, upd, 0, s, 1);
	}

	pair<int64_t, int64_t> query(int l, int r) {
		return query(l, r, 0, s, 1);
	}

	SegTree() {}
	SegTree(int size, vector<Info> data) :
		arr(4 * size), lazy(4 * size)
	{
		s = 1 << (int)(ceil(log2(size)));

		for (int i = 0; i < size; i++)
			arr[i + s] = data[i];
		for (int i = s - 1; i > 0; i--)
			arr[i] = merge(arr[2 * i], arr[2 * i + 1]);
	}
};

struct Fenwick {
	vector<int64_t> arr;

	void update(int x, int d) {
		for (; x < arr.size(); x += x & -x)
			arr[x] += d;
	}

	int64_t query(int x) {
		int64_t ans = 0;
		for (; x; x -= x & -x)
			ans += arr[x];
		return ans;
	}

	int64_t query(int l, int r) {
		return query(r - 1) - query(l - 1);
	}

	Fenwick() {}
	Fenwick(int n) : arr(n + 1) { }
};

struct Node {
	int dfs_in, dfs_out;
	int hld_start, hld_end, hld_pos;

	int deliveries;

	vector<int> children;
	int parent;
	int edge_weight;
	bool is_heavy;
};

int N;
SegTree hld;
Fenwick deliveries;
vector<int> hld_order;
vector<Node> nodes;

void init(int N, vector<int> U, vector<int> V, vector<int> T, vector<int> W) {
	::N = N;
	nodes.resize(N);
	deliveries = Fenwick(N);
	W[0]++;

	vector<vector<pair<int, int>>> adj(N);
	for (int i = 0; i < N - 1; i++) {
		adj[U[i]].emplace_back(V[i], T[i]);
		adj[V[i]].emplace_back(U[i], T[i]);
	}

	int dfs_pos = 1;
	vector<int> leafs;

	function<int(int, int)> dfs = [&](int node, int par) {
		deliveries.update(dfs_pos, W[node]);
		nodes[node].deliveries = W[node];
		nodes[node].dfs_in = dfs_pos++;

		int size = 1;
		pair<int, int> biggest_child = {INT_MIN, -1};
		for (auto [c, w]: adj[node]) {
			if (c == par) continue;

			nodes[node].children.push_back(c);
			nodes[c].parent = node;
			nodes[c].edge_weight = w;

			int c_size = dfs(c, node);
			size += c_size;
			biggest_child = max(biggest_child, make_pair(c_size, c));
		}

		if (biggest_child.second != -1) {
			nodes[biggest_child.second].is_heavy = true;
		} else {
			leafs.push_back(node);
		}

		nodes[node].dfs_out = dfs_pos;
		return size;
	};

	dfs(0, -1);
	nodes[0].parent = -1;

	vector<Info> hld_arr;
	hld_arr.reserve(N);

	int64_t total = deliveries.query(N);

	for (auto leaf: leafs) {
		int start = hld_arr.size();
		for (int l = leaf; l >= 0; l = (nodes[l].is_heavy ? nodes[l].parent : -1)) {
			int64_t del = deliveries.query(nodes[l].dfs_in, nodes[l].dfs_out);
			hld_arr.push_back({
				nodes[l].edge_weight,
				nodes[l].edge_weight * (total - del),
				nodes[l].edge_weight * del
			});
			hld_order.push_back(l);
		}
		int end = hld_arr.size();

		for (int i = start; i < end; i++) {
			nodes[hld_order[i]].hld_start = start;
			nodes[hld_order[i]].hld_end = end;
			nodes[hld_order[i]].hld_pos = i;
		}
	}

	hld = SegTree(N, hld_arr);
}

long long max_time(int S, int X) {
	if (S == 0) X++;
	int diff = X - nodes[S].deliveries;
	nodes[S].deliveries = X;

	deliveries.update(nodes[S].dfs_in, diff);

	hld.update(0, N, {diff, 0});
	for (
		int curr = S;
		curr != -1;
		curr = nodes[hld_order[nodes[curr].hld_end - 1]].parent
	) {
		hld.update(nodes[curr].hld_pos, nodes[curr].hld_end, {-diff, diff});
	}

	int64_t total = deliveries.query(1, N + 1);

	int node = 0;
	for (;;) {
		int on_path = *partition_point(
			hld_order.begin() + nodes[node].hld_start,
			hld_order.begin() + nodes[node].hld_pos + 1,
			[&](int n) {
				return deliveries.query(nodes[n].dfs_in, nodes[n].dfs_out) * 2 < total;
			}
		);

		int l = nodes[on_path].dfs_in + 1;
		auto ch = partition_point(
			nodes[on_path].children.begin(),
			nodes[on_path].children.end(),
			[&](int n) {
				return deliveries.query(l, nodes[n].dfs_out) * 2 < total;
			}
		);

		if (
			ch == nodes[on_path].children.end() ||
			deliveries.query(nodes[*ch].dfs_in, nodes[*ch].dfs_out) * 2 < total
		) {
			node = on_path;
			break;
		}
		node = *ch;
	}

	int64_t ans = hld.query(0, N).second;
	for (
		int curr = node;
		curr != -1;
		curr = nodes[hld_order[nodes[curr].hld_end - 1]].parent
	) {
		auto [hi, lo] = hld.query(nodes[curr].hld_pos, nodes[curr].hld_end);
		ans += hi - lo;
	}

	return 2 * 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...