Submission #1263628

#TimeUsernameProblemLanguageResultExecution timeMemory
1263628OgradLDynamic Diameter (CEOI19_diameter)C++20
100 / 100
2266 ms143616 KiB
#include <array>
#include <iostream>
#include <set>
#include <vector>
using namespace std;

long long n, q;
long long w;

struct segtree{

	int n, height;
	vector<long long> tree, lazy;

	segtree() {}

	segtree(int sz){
		n = sz;
		height = 32 - __builtin_clz(n);
		tree.assign(2 * n, 0);
		lazy.assign(n, 0);
	}

	void build_all(vector<long long>& v){
		for (int i = 0; i < v.size(); i++){
			tree[n + i] = v[i];
		}
		for (int i = n - 1; i > 0; --i) tree[i] = max(tree[i<<1], tree[i<<1|1]);
	}

	void apply(int p, long long value) {
		tree[p] += value;
		if (p < n) lazy[p] += value;
	}

	void build(int p) {
		while (p > 1) p >>= 1, tree[p] = max(tree[p<<1], tree[p<<1|1]) + lazy[p];
	}

	void push(int p) {
		for (int s = height; s > 0; --s) {
			int i = p >> s;
			if (lazy[i] != 0) {
				apply(i<<1, lazy[i]);
				apply(i<<1|1, lazy[i]);
				lazy[i] = 0;
			}
		}
	}

	void update(int l, int r, long long value) {
		l += n, r += n;
		int l0 = l, r0 = r;
		for (; l < r; l >>= 1, r >>= 1) {
			if (l&1) apply(l++, value);
			if (r&1) apply(--r, value);
		}
		build(l0);
		build(r0 - 1);
	}

	long long query(int l, int r) {
		l += n, r += n;
		push(l);
		push(r - 1);
		long long res = 0;
		for (; l < r; l >>= 1, r >>= 1) {
			if (l&1) res = max(res, tree[l++]);
			if (r&1) res = max(tree[--r], res);
		}
		return res;
	}
};

vector<vector<pair<int, long long>>> adj;
vector<vector<array<int, 3>>> ancestors;
vector<array<long long, 3>> edges;
vector<int> subtree_sz, removed;

vector<segtree> segtrees;
vector<vector<int>> tins, touts;
vector<vector<long long>> tours;
vector<int> timers;

vector<multiset<long long>> max_dists;
multiset<long long> max_diams;

int find_subtree_sz(int v, int p = 0){
	subtree_sz[v] = 1;
	for (auto [x, w] : adj[v]){
		if (x != p && !removed[x])
			subtree_sz[v] += find_subtree_sz(x, v);
	}
	return subtree_sz[v];
}

int find_centroid(int v, int sz, int p = 0){
	for (auto [x, w] : adj[v]){
		if (x == p || removed[x]) continue;
		if (subtree_sz[x] * 2 >= sz)
			return find_centroid(x, sz, v);
	}
	return v;
}

void assign_ancestors(int v, int p, int level, int child_idx, int centroid, int d, long long total_w){
	tins[level][v] = timers[level]++;
	tours[level][tins[level][v]] = total_w;
	ancestors[v].push_back({centroid, d, child_idx});
	for (auto [x, w] : adj[v]){
		if (removed[x] || x == p) continue;
		assign_ancestors(x, v, level, child_idx, centroid, d + 1, total_w + w);
	}
	touts[level][v] = timers[level];
}

long long get_max_diam(int k){
	long long res = 0;
	auto it = max_dists[k].rbegin();
	res += *it;
	res += *next(it);
	return res;
}

void build_centroid(int v, int level = 0, int build_ms = 0){
	find_subtree_sz(v);
	int centroid = find_centroid(v, subtree_sz[v]);

	removed[centroid] = 1;
	if (!build_ms){
		ancestors[centroid].push_back({centroid, 0, -1});
	} else {
		max_dists[centroid].insert(0);
		max_dists[centroid].insert(0);
	}

	for (auto [x, w] : adj[centroid]){
		if (removed[x]) continue;
		if (!build_ms){
			assign_ancestors(x, centroid, level, x, centroid, 1, w);
		} else {
			long long diam = segtrees[level].query(tins[level][x], touts[level][x]);
			max_dists[centroid].insert(diam);
		}
		build_centroid(x, level + 1, build_ms);
	}

	if (build_ms){
		max_diams.insert(get_max_diam(centroid));
	}
}

void update_multiset(multiset<long long>& mset, long long pre, long long nxt){
	auto it = mset.find(pre);
	mset.erase(it);

	mset.insert(nxt);
}

void update(int k, long long e){
	auto& [a, b, w] = edges[k];

	long long diff = e - w;

	int min_sz = min(ancestors[a].size(), ancestors[b].size());

	for (int i = 0; i < min_sz; i++){
		if (ancestors[a][i][1] < ancestors[b][i][1]){
			swap(a, b);
		}

		auto [centroid, dist, idx_child] = ancestors[a][i];
		
		// increase a subtree distances by diff
		long long pre_max = segtrees[i].query(tins[i][idx_child], touts[i][idx_child]);

		segtrees[i].update(tins[i][a], touts[i][a], diff);

		long long nxt_max = segtrees[i].query(tins[i][idx_child], touts[i][idx_child]);

		if (pre_max == nxt_max)
			continue;

		// update max_dist[centroid]
		long long pre_diam = get_max_diam(centroid);

		update_multiset(max_dists[centroid], pre_max, nxt_max);

		long long nxt_diam = get_max_diam(centroid);

		if (pre_diam == nxt_diam)
			continue;

		// update max_diams
		update_multiset(max_diams, pre_diam, nxt_diam);
	}

	w = e;
}

long long get_answer(){
	return *max_diams.rbegin();
}

int main(){

	ios_base::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);

	cin >> n >> q >> w;

	adj.resize(n);
	
	long long a, b, c;
	for (int i = 0; i < n-1; i++){
		cin >> a >> b >> c;
		--a, --b;

		adj[a].push_back({b, c});
		adj[b].push_back({a, c});
		edges.push_back({a, b, c});
	}

	removed.assign(n, 0);
	subtree_sz.assign(n, -1);
	ancestors.resize(n);

	segtrees.assign(18, segtree(n));
	tins.assign(18, vector<int>(n));
	touts.assign(18, vector<int>(n));
	tours.assign(18, vector<long long>(n));
	timers.assign(18, 0);

	max_dists.resize(n);

	build_centroid(0);

	for (int i = 0; i < 18; i++){
		segtrees[i].build_all(tours[i]);
	}

	removed.assign(n, 0);
	build_centroid(0, 0, 1);

	long long last = 0;
	long long d, e;

	while (q--){
		cin >> d >> e;

		d = (d + last) % (n - 1);
		e = (e + last) % w;

		update(d, e);

		last = get_answer();

		cout << last << "\n";
	}

	return 0;
}
#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...