Submission #1357709

#TimeUsernameProblemLanguageResultExecution timeMemory
1357709WH8Dynamic Diameter (CEOI19_diameter)C++17
42 / 100
5096 ms262556 KiB
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace __gnu_pbds;
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define f first
#define all(x) x.begin(),x.end()
#define s second
#define pll pair<long long, long long>
#define sz(x) (int)x.size()

const int maxn=100005, maxq=100005, inf=2e18+5;
struct node{
	int s, e, m, v, lz;
	node *l, *r;
	node(int S, int E){
		s=S, e=E, m=(s+e)/2, v=0, lz=0;
		if(s!=e){
			l=new node(s, m);
			r=new node(m+1, e);
		}
	}
	void prop(){
		if(lz==0 or s==e) return;
		l->v += lz, r->v += lz, l->lz += lz, r->lz += lz;
		lz=0;
	}
	int combine(int a, int b){
		return max(a, b);
	}
	void upd(int S, int E, int DV){
		if(S<=s and e<=E){
			v += DV;
			lz += DV;
			return;
		}
		prop();
		if(E <= m) l->upd(S, E, DV);
		else if(S > m)r->upd(S, E, DV);
		else l->upd(S, m, DV), r->upd(m+1, E, DV);
		v=combine(l->v, r->v);
	}
	int qry(int S, int E){
		if(S<=s and e<=E){
			return v;
		}
		prop();
		if(E <= m) return l->qry(S,E);
		else if(S > m) return r->qry(S,E);
		return combine(l->qry(S, m), r->qry(m+1, E));
	}
} *root[maxn];
int n, q, w;
vector<vector<pair<int,int>>> al(maxn);
vector<int> lay(maxn, inf), ss(maxn), st(maxn, 0), oridep(maxn, 0), len(maxn, 0), cpar(maxn);
vector<vector<int>> in(maxn), out(maxn);
multiset<pll> cands;
vector<int> centans(maxn);
vector<multiset<pll>> path(maxn), childinpathvalue(maxn);
int t=0;
void subtree_size(int x, int p, int layer){
	ss[x]=1;
	for(auto [it, w] : al[x]){
		if(it==p or lay[it] <= layer)continue;
		subtree_size(it, x, layer);
		ss[x] += ss[it];
	}
}
int find_centroid(int x, int p, int layer, int full){
	for(auto [it, w] : al[x]){
		if(it==p or lay[it] <= layer)continue;
		if(ss[it] > full/2) return find_centroid(it, x, layer, full);
	}
	return x;
}
void dfs(int x, int p, int head, int cd){
	root[head]->upd(t, t, cd);
	in[x].push_back(t++);
	for(auto [it, w] : al[x]){
		if(it == p or lay[it] <= lay[head])continue;
		if(lay[head] == 0){
			len[it]=w;
			oridep[it]=oridep[x]+1;
		}
		int beft=t;
		dfs(it, x, head, cd + w);
		if(p == -1){
			int childdep=root[head]->qry(beft, t-1);
			path[head].insert({childdep, beft});
			childinpathvalue[head].insert({beft, childdep});
		}
	}
	out[x].push_back(t-1);
}

int calcdia(int cent){
	int top1=(sz(path[cent]) >= 1 ? prev(path[cent].end())->f : 0);
	int top2=(sz(path[cent]) >= 2 ? prev(prev(path[cent].end()))->f : 0);
	return top1+top2;
}

int build(int x, int par, int layer){
	subtree_size(x, -1, layer);
	int cent=find_centroid(x, -1, layer, ss[x]);
	lay[cent]=layer;
	t=0;
	root[cent]=new node(0, ss[x]-1);

	dfs(cent, -1, cent, 0);
	centans[cent] = calcdia(cent);
	cands.insert({centans[cent], cent});
	childinpathvalue[cent].insert({ss[x], 0});
	/*printf("centroid %lld subtree size %lld", cent, ss[x]);
	cout<<endl;
	printf("centroid %lld, paths : ", cent); 
	for(auto [tin, leng] : childinpathvalue[cent]) printf(" (%lld, %lld) ", tin, leng);
	cout<<endl;
	printf("centroid %lld, dia here is %lld\n\n", cent, centans[cent]);*/
	cpar[cent]=par;
	//printf("centroid %lld layer %lld, parent %lld\n", cent, layer, par);
	for(auto [it, w] : al[cent]){
		if(lay[it] == inf) build(it, cent, layer+1);
	}
	return cent;
}

signed main(){
	//ios_base::sync_with_stdio(false);
	//cin.tie(0);
	cin>>n>>q>>w;
	vector<pll> ed(n-1);
	for (int i=1;i<=n-1;i++){
		int a,b,c;cin>>a>>b>>c;
		ed[i-1] = {a, b};
		al[a].push_back({b,c});
		al[b].push_back({a,c});
	}
	build(1, -1, 0);
	/*for(int i=1;i<=n;i++){
		cout<<len[i]<<" "<<oridep[i]<<"\n";
	}
	cout<<endl;*/
	/*for(int i=1;i<=n;i++){
		printf("node i %lld : \n", i);
		for(auto j : in[i]){
			cout<<j <<" ";
		}
		cout<<endl;
		for(auto j : out[i]){
			cout<<j <<" ";
		}
		for(int j=0;j<(int)in[i].size();j++){
			printf(" (%lld, %lld) ", in[i][j], out[i][j]);
		}
		cout<<endl;
	}*/
	int last=0;
	for(int qind=0;qind<q;qind++){
		int eind, nww;cin>>eind>>nww;
		eind = (eind + last) % (n-1);
		nww = (nww + last) % w;
		auto [x, y] = ed[eind];
		assert(lay[x] != lay[y]);
		assert(oridep[x] != oridep[y]);
		int cn=(lay[x] < lay[y] ? x : y);
		int lower=(oridep[x] < oridep[y] ? y : x);
		int dv=nww-len[lower];
		//printf("x %lld y %lld, %lld nww %lld\n", x, y, lower, nww);
		//printf("dv is %lld\n", dv);
		len[lower]=nww;
		while(cn != -1){
			int tofind=(in[x][lay[cn]] < in[y][lay[cn]] ? y : x);
			auto it = upper_bound(all(childinpathvalue[cn]), make_pair(in[tofind][lay[cn]], (int)1e15));
			assert(it != childinpathvalue[cn].end() and it != childinpathvalue[cn].begin());
			auto [intime, bestpath] = *prev(it);
			auto [nextintime, _b] = *it;
			childinpathvalue[cn].erase(prev(it));
			auto pathentry = path[cn].find({bestpath, intime});
			assert(pathentry != path[cn].end());
			path[cn].erase(pathentry);
			auto candsentry = cands.find({centans[cn], cn});
			assert(candsentry != cands.end());
			cands.erase(candsentry);
			if(in[x][lay[cn]] < in[y][lay[cn]]){ // x is higher than y, upd y subtree
				root[cn]->upd(in[y][lay[cn]], out[y][lay[cn]], dv);
			}
			else {//update x subtree;
				root[cn]->upd(in[x][lay[cn]], out[x][lay[cn]], dv);
			}
			int nwpath=root[cn]->qry(intime, nextintime-1);
			childinpathvalue[cn].insert({intime, nwpath});
			path[cn].insert({nwpath, intime});
			centans[cn] = calcdia(cn);
			cands.insert({centans[cn], cn});
			cn = cpar[cn];
		}
		last = prev(cands.end())->f;
		cout<<last<<'\n';
	}
}
#Result Execution timeMemoryGrader output
Fetching results...
#Result Execution timeMemoryGrader output
Fetching results...
#Result Execution timeMemoryGrader output
Fetching results...
#Result Execution timeMemoryGrader output
Fetching results...
#Result Execution timeMemoryGrader output
Fetching results...
#Result Execution timeMemoryGrader output
Fetching results...