Submission #1242705

#TimeUsernameProblemLanguageResultExecution timeMemory
1242705errayTree (IOI24_tree)C++20
100 / 100
144 ms58304 KiB
#include <bits/stdc++.h>

#include "tree.h"

using namespace std;

#ifdef DEBUG
	#include "debug.h"
#else 
	#define debug(...) void(37)
#endif

struct DSU {
	vector<int> link, leaves;
	DSU(vector<int> _leaf_count) {
		leaves = _leaf_count;
		int n = int(leaves.size());
		link.resize(n);
		iota(link.begin(), link.end(), 0);
	}
	int get(int v) {
		return link[v] = link[v] == v ? v : get(link[v]);
	}
	bool unite(int x, int y) {
		x = get(x), y = get(y);
		if (x == y) return false;
		link[y] = x;
		leaves[x] += leaves[y] - 1;
		return true;
	}
	int leaf_count(int v) {
		return leaves[get(v)];
	}
};

struct linear_sum {
	int64_t L_coeff, R_coeff;
	int64_t eval(int L, int R) {
		return L_coeff * L + R_coeff * R;
	}
	linear_sum init() {
		L_coeff = 0, R_coeff = 0;
		return *this;
	}
};
linear_sum operator+(linear_sum l, linear_sum r) {
	l.L_coeff += r.L_coeff;
	l.R_coeff += r.R_coeff;
	return l;
}
linear_sum operator-(linear_sum l, linear_sum r) {
	l.L_coeff -= r.L_coeff;
	l.R_coeff -= r.R_coeff;
	return l;
}
linear_sum operator-(const linear_sum& x) {
	return linear_sum{}.init() - x;
}



vector<linear_sum> pref_sums;
vector<int> placer;
int64_t leaf_sums;

void init(std::vector<int> P, std::vector<int> W) {
	int N = int(P.size());
	vector<int> degree(N);
	for (int i = 1; i < N; ++i) degree[P[i]]++;
	for (int i = 0; i < N; ++i) {
		if (degree[i] == 0) {
			degree[i] = 1;
			leaf_sums += W[i];
		}
	}
	DSU dsu(degree);
	vector<int> node_ord(N); iota(node_ord.begin(), node_ord.end(), 0);
	sort(node_ord.begin(), node_ord.end(), [&](int x, int y) {
		return W[x] > W[y];
	});
	vector<vector<int>> waiting(N);
	vector<bool> act(N);
	vector<pair<int, linear_sum>> events;
	for (auto v : node_ord) {
		act[v] = true;
		vector<int> sizes;
		for (auto u : waiting[v]) {
			sizes.push_back(dsu.leaf_count(u));
			dsu.unite(v, u);
		}
		int subtree = dsu.leaf_count(v);
		if (P[v] != -1) {
			if (act[P[v]]) dsu.unite(P[v], v);
			else waiting[P[v]].push_back(v);
		}
		int root = dsu.leaf_count(v);
		auto Add = [&](int t, linear_sum x) {
			x.R_coeff *= W[v], x.L_coeff *= W[v];
			events.push_back({t, x});
		};
		debug(v, subtree, root, sizes);

		//target: L + (R - (r - s + 1) * L) when R > (r - s + 1) * L, else L 
		auto target = linear_sum{1 - root + subtree - 1, +1};
		int to_bigger_target_cut = (root - subtree + 1);

		int mandatory_value_cut = subtree;
		//R < subtree * L
		{
			Add(0, {-1, 0}); // R - L
			Add(to_bigger_target_cut, -target + linear_sum{+1, 0}); //R - target

			//sums - R
			int non_leaf_c = int(sizes.size());
			int non_leaf_leaves = accumulate(sizes.begin(), sizes.end(), 0);
			Add(0, {subtree - non_leaf_leaves, non_leaf_c});
			for (auto s : sizes) {
				Add(s, {s, -1});
			}
		}

		//R > subtree * L
		{
			//Add(mandatory_value_cut, {subtree, 0}); maintained from the top
			Add(root, target - linear_sum{subtree, 0});		
		}
	}
	sort(events.begin(), events.end(), [&](auto x, auto y) {
		return x.first < y.first;
	});
	int s = int(events.size());
	pref_sums.resize(s + 1);
	placer.resize(s);
	for (int i = 0; i < s; ++i) {
		placer[i] = events[i].first;
		pref_sums[i + 1] = pref_sums[i] + events[i].second;
	}
}

long long query(int L, int R) {
	int p = int(lower_bound(placer.begin(), placer.end(), array<int, 2>{L, R}, [&](int x, array<int, 2> lr) {
		return int64_t(lr[0]) * x < lr[1];
	}) - placer.begin());
	return leaf_sums * L + pref_sums[p].eval(L, R); 
} 
#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...
#Verdict Execution timeMemoryGrader output
Fetching results...