제출 #1220921

#제출 시각아이디문제언어결과실행 시간메모리
1220921MateiKing80Dynamic Diameter (CEOI19_diameter)C++20
49 / 100
5079 ms492384 KiB
#include <bits/stdc++.h>

using namespace std;

using ll = long long;
#define int ll

using pii = pair<int, int>;
#define fr first
#define sc second

const int N = 1e5 + 5;

struct Edge {
	int u, v, w;
};

struct segTree {
	vector<int> aint;
	vector<int> lazy;
	
	void init(int n) {
		aint.resize(4 * n + 5, 0);
		lazy.resize(4 * n + 5, 0);
	}
	
	void propag(int pos) {
		if (lazy[pos] == 0)
			return;
		aint[pos] += lazy[pos];
		if (2 * pos + 1 < (int)lazy.size()) {
			lazy[2 * pos] += lazy[pos];
			lazy[2 * pos + 1] += lazy[pos];
		}
		lazy[pos] = 0;
	}
	
	void update(int pos, int st, int dr, int l, int r, int val) {
		propag(pos);
		if (l <= st && dr <= r) {
			lazy[pos] += val;
			propag(pos);
			return;
		}
		int mid = (st + dr) >> 1;
		
		if (l <= mid)
			update(2 * pos, st, mid, l, r, val);
		else
			propag(2 * pos);
	
		if (mid < r)
			update(2 * pos + 1, mid + 1, dr, l, r, val);
		else
			propag(2 * pos + 1);
			
		aint[pos] = max(aint[2 * pos], aint[2 * pos + 1]);
	}
	
	int query(int pos, int st, int dr, int l, int r) {
		propag(pos);
		if (l <= st && dr <= r)
			return aint[pos];
		int mid = (st + dr) >> 1;
		if (r <= mid)
			return query(2 * pos, st, mid, l, r);
		if (mid < l)
			return query(2 * pos + 1, mid + 1, dr, l, r);
		return max(query(2 * pos, st, mid, l, r), query(2 * pos + 1, mid + 1, dr, l, r));
	}
};

struct Tree {
	int root, n, timer = 0;
	vector<Edge> edges;
	vector<vector<pii>> vec;
	map<int, int> deNorm;
	set<pii> dists;
	vector<int> ancestor, depth, tin, tout, toLeaf;
	segTree ds;
	
	void addEdge(int u, int v, int w) {
		edges.push_back({u, v, w});
	}
	
	void addVec() {
		n = edges.size() + 1;
		vec.resize(n);
		depth.resize(n, 0);
		tin.resize(n, 0);
		tout.resize(n, 0);
		toLeaf.resize(n, 0);
		ancestor.resize(n, root);
		ds.init(n);
		
		map<int, int> mp;
		for (auto [u, v, w] : edges)
			mp[u] ++, mp[v] ++;
		int cnt = 0;
		for (auto [i, j] : mp)
			deNorm[i] = cnt ++;
		for (auto [u, v, w] : edges) {
			vec[deNorm[u]].push_back({deNorm[v], w});
			vec[deNorm[v]].push_back({deNorm[u], w});
		}
		root = deNorm[root];
	}
	
	int dfs(int nod, int papa, int anc, int distUp) {
		tin[nod] = ++timer;
		depth[nod] = 1 + depth[papa];
		ds.update(1, 1, n, tin[nod], tin[nod], distUp);
		ancestor[nod] = anc;
		int maxx = 0;
		for (auto [i, j] : vec[nod]) {
			if (i == papa)
				continue;
			maxx = max(maxx, j + dfs(i, nod, anc, distUp + j));
		}
		tout[nod] = timer;
		return maxx;
	}
	
	void init() {
		addVec();
		ds.init(n);
		tin[root] = ++timer;
		for (auto [i, j] : vec[root]) {
			toLeaf[i] = j + dfs(i, root, i, j);
			dists.insert({toLeaf[i], i});
		}
		tout[root] = timer;
	}
	
	void update(int u, int v, int diff) {
		u = deNorm[u];
		v = deNorm[v];		

		if (depth[u] < depth[v])
			swap(u, v);
		ds.update(1, 1, n, tin[u], tout[u], diff);
		dists.erase({toLeaf[ancestor[u]], ancestor[u]});
		toLeaf[ancestor[u]] = ds.query(1, 1, n, tin[ancestor[u]], tout[ancestor[u]]);
		dists.insert({toLeaf[ancestor[u]], ancestor[u]});
	}
	
	int query() {
		if (n == 1)
			return 0;
		if (vec[root].size() == 1)
			return (*dists.begin()).fr;
		int ans = 0;
		auto it = dists.end();
		it --;
		ans += (*it).fr;
		it --;
		ans += (*it).fr;
		return ans;
	}
} ds[N];

set<pii> s;
vector<pii> vec[N];
int papaC[N];
int depthCentr[N];

bool isCentroid[N];
int sz[N];

void dfsSz(int nod, int papa) {
	sz[nod] = 1;
	for (auto [i, j] : vec[nod])
		if (i != papa && !isCentroid[i]) {
			dfsSz(i, nod);
			sz[nod] += sz[i];
		}
}

int centr(int nod, int papa, int target) {
	for (auto [i, j] : vec[nod])
		if (!isCentroid[i] && i != papa && sz[i] >= target)
			return centr(i, nod, target);
	return nod;
}

void dfsAddDs(int nod, int papa, int c) {
	for (auto [i, j] : vec[nod]) {
		if (i != papa && !isCentroid[i]) {
			ds[c].addEdge(i, nod, j);
			dfsAddDs(i, nod, c);
		}
	}
}

void dfsCentroid(int nod, int papaCentr) {
	dfsSz(nod, 0);
	int c = centr(nod, 0, (sz[nod] + 1) / 2);
	//cout << c << '\n';
	papaC[c] = papaCentr;
	depthCentr[c] = 1 + depthCentr[papaCentr];
	isCentroid[c] = true;
	dfsAddDs(c, 0, c);
	for (auto [i, j] : vec[c])
		if (!isCentroid[i])
			dfsCentroid(i, c);
}

signed main() {
	ios_base::sync_with_stdio(false);
	cin.tie(0);
	
	int n, q, useless;
	cin >> n >> q >> useless;
	for (int i = 1; i <= n; i ++)
		ds[i].root = i;
	vector<Edge> edges;
	for (int i = 1; i < n; i ++) {
		int u, v, w;
		cin >> u >> v >> w;
		edges.push_back({u, v, w});
		vec[u].push_back({v, w});
		vec[v].push_back({u, w});
	}
	dfsCentroid(1, 0);
	for (int i = 1; i <= n; i ++) {	
		ds[i].init();
		s.insert({ds[i].query(), i});
	}
	int last = 0;
	while (q --) {
		int d, e;
		cin >> d >> e;
		d = (d + last) % (n - 1) + 1;
		d --;
		e = (e + last) % useless;
		int u = edges[d].u;
		int v = edges[d].v;
		int w = e - edges[d].w;
		if (depthCentr[u] > depthCentr[v])
			swap(u, v);	
		
		int curr = u;
		while (curr) {
			s.erase({ds[curr].query(), curr});
			ds[curr].update(u, v, w);
			s.insert({ds[curr].query(), curr});
			curr = papaC[curr];
		}
		last = (*s.rbegin()).fr;
		edges[d].w = e;
		cout << last << '\n';
	}
}
#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...