#include <bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define gcd __gcd
#define sz(v) (int) v.size()
#define pb push_back
#define pi pair<int,int>
#define all(v) (v).begin(), (v).end()
#define compact(v) (v).erase(unique(all(v)), (v).end())
#define FOR(i, a, b) for(int i = (a); i <= (b); i++)
#define dbg(x) "[" #x " = " << (x) << "]"
//#define int long long
using ll = long long;
using ld = long double;
using ull = unsigned long long;
template<typename T> bool ckmx(T& a, const T& b){if(a < b) return a = b, true; return false;}
template<typename T> bool ckmn(T& a, const T& b){if(a > b) return a = b, true; return false;}
const int N = 1e5+5;
const ll MOD = 1e9+7;
const ll INF = 1e18;
struct Edge{
int u,v; ll w;
Edge(int u = 0, int v = 0, ll w = 0): u(u), v(v), w(w) {}
};
int n, q; ll W;
Edge iE[N]; pair<ll,ll> Q[N];
namespace Subtask12{
bool checkSubtask(){
return n <= 5e3 && W <= 10e3;
}
const int N = 5e3 + 5;
int dp[N]; vector<int> adj[N];
Edge E[N];
void buildGraph(){
FOR(i, 1, n-1){
E[i] = iE[i];
int u = E[i].u, v = E[i].v;
adj[u].pb(i), adj[v].pb(i);
}
}
int diameter(int x = 1, int p = -1){
int answer = 0, mx1 = 0, mx2 = 0;
dp[x] = 0;
for(int id : adj[x]){
int v = E[id].u ^ E[id].v ^ x, w = E[id].w;
if(v != p){
answer = max(answer, diameter(v, x));
dp[x] = max(dp[x], dp[v] + w);
if(mx1 <= dp[v] + w){
mx2 = mx1;
mx1 = dp[v] + w;
}
else if(mx2 <= dp[v] + w){
mx2 = dp[v] + w;
}
}
}
answer = max(answer, mx1 + mx2);
return answer;
}
void process()
{
int last = 0; buildGraph();
FOR(i, 1, q){
int dj = (Q[i].fi + last) % (n - 1) + 1;
int ej = (Q[i].se + last) % W;
E[dj].w = ej;
cout << (last = diameter()) <<"\n";
}
return;
}
}
namespace Subtask3{
bool checkSubtask(){
int cnt = 0;
FOR(i, 1, n - 1) cnt += (iE[i].u == 1 || iE[i].v == 1);
return (cnt == n - 1);
}
Edge E[N];
void process()
{
multiset<int> maxW;
FOR(i, 1, n - 1){
E[i] = iE[i];
maxW.insert(E[i].w);
}
int last = 0;
FOR(i, 1, q){
int dj = (Q[i].fi + last) % (n - 1) + 1;
int ej = (Q[i].se + last) % W;
maxW.erase(maxW.find(E[dj].w));
E[dj].w = ej; maxW.insert(E[dj].w);
auto it = (--maxW.end());
last = *it;
if(it != maxW.begin()){
--it; last += *it;
}
cout << last <<"\n";
}
return;
}
}
struct SMT_POINTMAX{
int trsz;
vector<ll> st;
SMT_POINTMAX(int n = 0): trsz(n), st((n << 2 | 1) + 1) {}
void init(int n){
trsz = n;
st.resize((n << 2 | 1) + 1);
return;
}
void update(int id, int l, int r, int x, ll val){
if(l == r){
st[id] = val;
return;
}
else{
int m = (l+r)>>1;
if(x <= m) update(id<<1, l, m, x, val);
else{
update(id<<1|1, m+1, r, x, val);
}
st[id] = max(st[id<<1], st[id<<1|1]);
}
return;
}
ll answer(){return st[1];}
void update(int x, ll val){return update(1, 1, trsz, x, val), void();}
};
namespace Subtask4{
bool checkSubtask()
{
FOR(i, 1, n-1){
if(iE[i].u < iE[i].v){
if(iE[i].u != (iE[i].v / 2)){
return false;
}
}
else{
if((iE[i].u / 2) != iE[i].v){
return false;
}
}
}
return true;
}
int dp[N], par[N];
multiset<int, greater<int>> maxW[N], answer;
vector<int> adj[N], g[N], saveDP[N];
Edge E[N];
SMT_POINTMAX st;
void preDFS(int x = 1, int p = -1){
for(int id : adj[x]){
int v = E[id].u ^ E[id].v ^ x;
if(v != p){
g[x].push_back(v);
par[v] = id;
preDFS(v, x);
}
}
sort(all(g[x]));
saveDP[x].assign(sz(g[x]), -1);
return;
}
void buildGraph(){
FOR(i, 1, n - 1){
E[i] = iE[i];
int u = E[i].u, v = E[i].v;
if(u > v) swap(E[i].u, E[i].v);
adj[u].pb(i), adj[v].pb(i);
}
return;
}
void recalc(int node){
if(!maxW[node].size()){
st.update(node, 0);
return;
}
if(maxW[node].size() == 1){
st.update(node, (*maxW[node].begin()));
}
else{
auto it = maxW[node].begin();
int last = *it; ++it; last += *it;
st.update(node, last);
}
return;
}
void rmv(int x){
int prenode = x, node = x / 2, curDP = dp[x];
while(node){
curDP = curDP + E[par[prenode]].w;
int id = lower_bound(all(g[node]), prenode) - g[node].begin();
if(saveDP[node][id] > 0){
maxW[node].erase(maxW[node].find(saveDP[node][id]));
saveDP[node][id] = -1;
}
prenode = node;
node = node / 2;
}
return;
}
void add(int x){
int prenode = x, node = x / 2, curDP = dp[x];
while(node){
curDP = curDP + E[par[prenode]].w;
// Erase old value (if old value is < new value)
int id = lower_bound(all(g[node]), prenode) - g[node].begin();
if(curDP > saveDP[node][id]){
if(saveDP[node][id] > 0){
assert(maxW[node].find(saveDP[node][id]) != maxW[node].end());
maxW[node].erase(maxW[node].find(saveDP[node][id]));
}
// Add new value
saveDP[node][id] = curDP;
maxW[node].insert(curDP);
// Recalculate
assert(maxW[node].size());
recalc(node);
dp[node] = *maxW[node].begin();
}
curDP = dp[node];
prenode = node;
node = node / 2;
}
return;
}
void process()
{
buildGraph(), preDFS(); st.init(n);
FOR(i, 1, n) add(i);
int last = 0;
FOR(i, 1, q){
int dj = (Q[i].fi + last) % (n - 1) + 1;
int ej = (Q[i].se + last) % W;
rmv(E[dj].v);
E[dj].w = ej;
add(E[dj].v);
cout << (last = st.answer()) <<"\n";
}
return;
}
}
struct SMT_MAXRANGE{
int trsz;
vector<ll> st, laz;
void init(int n){
trsz = n;
st.resize((n << 2 | 1) + 1);
laz.resize((n << 2 | 1) + 1);
return;
}
void apply(int id, ll val){
st[id] += val;
laz[id] += val;
return;
}
void down(int id){
ll val = laz[id]; laz[id] = 0;
if(!val) return;
apply(id<<1, val);
apply(id<<1|1, val);
return;
}
void update(int id, int l, int r, int u, int v, ll val){
if(l > v || r < u) return;
if(l >= u && r <= v){
apply(id, val);
return;
}
down(id);
int m = (l+r)>>1;
update(id<<1, l, m, u, v, val);
update(id<<1|1, m+1, r, u, v, val);
st[id] = max(st[id<<1], st[id<<1|1]);
return;
}
ll get(int id, int l, int r, int u, int v){
if(l > v || r < u) return 0;
if(l >= u && r <= v) return st[id];
down(id);
int m = (l+r)>>1;
return max(get(id<<1, l, m, u, v), get(id<<1|1, m+1, r, u, v));
}
void update(int l, int r, ll val){
return update(1, 1, trsz, l, r, val), void();
}
ll get(int l, int r){
return get(1, 1, trsz, l, r);
}
};
namespace Subtask5{
SMT_MAXRANGE st;
int timerDFS, tin[N], tout[N];
ll depth[N];
vector<pair<int,ll>> adj[N];
Edge E[N];
void preDFS(int x = 1, int p = -1){
tin[x] = ++timerDFS;
for(pair<int,ll> e : adj[x]){
int v = e.fi; ll w = e.se;
if(v != p){
depth[v] = depth[x] + w;
preDFS(v, x);
}
}
tout[x] = timerDFS;
return;
}
void buildGraph()
{
FOR(i, 1, n - 1){
E[i] = iE[i];
int u = E[i].u, v = E[i].v; ll w = E[i].w;
adj[u].pb(make_pair(v, w));
adj[v].pb(make_pair(u, w));
}
}
void process()
{
buildGraph();
preDFS(); st.init(timerDFS);
FOR(i, 1, n){
st.update(tin[i], tin[i], depth[i]);
}
multiset<ll, greater<ll>> maxW;
sort(all(adj[1]), [&](pair<int,int> x, pair<int,int> y){return tin[x.fi] < tin[y.fi];});
vector<int> g; vector<ll> DP;
for(pair<int,int> v : adj[1]){
DP.push_back(st.get(tin[v.fi], tout[v.fi]));
g.push_back(tin[v.fi]);
maxW.insert(DP.back());
}
ll last = 0;
FOR(i, 1, q){
ll dj = (Q[i].fi + last) % (n - 1) + 1;
ll ej = (Q[i].se + last) % W;
int u = E[dj].u, v = E[dj].v;
if(tin[u] > tin[v]) swap(u, v);
st.update(tin[v], tout[v], ej - E[dj].w);
E[dj].w = ej;
int id = upper_bound(all(g), tin[v]) - g.begin() - 1;
int x = adj[1][id].fi;
assert(id >= 0 && id < (int)g.size());
assert(maxW.find(DP[id]) != maxW.end());
maxW.erase(maxW.find(DP[id]));
DP[id] = st.get(tin[x], tout[x]);
maxW.insert(DP[id]);
last = *maxW.begin();
if(maxW.size() > 1){
last = last + (*(++maxW.begin()));
}
cout << last <<"\n";
}
return;
}
}
namespace Subtask6{
const int lg = 21;
// timerDFS
int timerDFS[lg], tin[lg][N], tout[lg][N];
// data
ll depth[lg][N];
SMT_MAXRANGE st[lg]; SMT_POINTMAX saveCenMax;
vector<ll> saveDP[N]; vector<ll> idFind[N];
multiset<ll, greater<ll>> maxD[N];
// Centroid
int sz[N], lvl[N], headCen[lg][N]; bool del[N];
// Tree
vector<pair<int,ll>> adj[N]; Edge E[N];
int csz(int x, int p){
sz[x] = 1;
for(pair<int,ll> v : adj[x]){
if(!del[v.fi] && v.fi != p){
sz[x] += csz(v.fi, x);
}
}
return sz[x];
}
int Centroid(int x, int p, int trsz){
for(pair<int,ll> v : adj[x]){
if(v.fi != p && !del[v.fi] && sz[v.fi] > trsz / 2) return Centroid(v.fi, x, trsz);
}
return x;
}
void dfs(int x, int p, int cenID, int lvlCen){
tin[lvlCen][x] = ++timerDFS[lvlCen];
headCen[lvlCen][x] = cenID;
for(pair<int,ll> e : adj[x]){
int v = e.fi; ll w = e.se;
if(!del[v] && v != p){
depth[lvlCen][v] = depth[lvlCen][x] + w;
dfs(v, x, cenID, lvlCen);
}
}
tout[lvlCen][x] = timerDFS[lvlCen];
st[lvlCen].update(tin[lvlCen][x], tin[lvlCen][x], depth[lvlCen][x]);
return;
}
void buildCentroid(int x, int direct_parCen){
x = Centroid(x, -1, csz(x, -1));
int lvlCen = lvl[direct_parCen] + 1;
lvl[x] = lvlCen;
del[x] = true;
dfs(x, -1, x, lvlCen);
sort(all(adj[x]), [&](pair<int,ll> x, pair<int,ll> y){
return tin[lvlCen][x.fi] < tin[lvlCen][y.fi];
});
for(pair<int,ll> e : adj[x]){
int v = e.first;
saveDP[x].push_back(st[lvlCen].get(tin[lvlCen][v], tout[lvlCen][v]));
maxD[x].insert(saveDP[x].back());
idFind[x].push_back(tin[lvlCen][v]);
}
for(pair<int,int> v : adj[x]){
if(!del[v.fi]){
buildCentroid(v.fi, x);
}
}
return;
}
void reCalc(int x){
if(!maxD[x].size()){
saveCenMax.update(x, 0);
return;
}
else if(maxD[x].size() == 1){
saveCenMax.update(x, *maxD[x].begin());
}
else{
ll last = *maxD[x].begin();
last = last + (*(++maxD[x].begin()));
saveCenMax.update(x, last);
}
return;
}
void updateCentroid(int u, int v, ll new_val, ll old_val){
int curLvl = lg - 1;
while(curLvl){
if(headCen[curLvl][u] && headCen[curLvl][u] == headCen[curLvl][v]){
if(tin[curLvl][u] > tin[curLvl][v]) swap(u, v);
int x = headCen[curLvl][u];
int id = upper_bound(all(idFind[x]), tin[curLvl][v]) - idFind[x].begin() -1;
assert(maxD[x].find(saveDP[x][id]) != maxD[x].end());
maxD[x].erase(maxD[x].find(saveDP[x][id]));
st[curLvl].update(tin[curLvl][v], tout[curLvl][v], new_val - old_val);
int par_v = adj[x][id].fi;
saveDP[x][id] = st[curLvl].get(tin[curLvl][par_v], tout[curLvl][par_v]);
maxD[x].insert(saveDP[x][id]);
reCalc(x);
}
curLvl--;
}
}
void preprocess()
{
FOR(i, 1, n - 1){
E[i] = iE[i];
int u = E[i].u, v = E[i].v; ll w = E[i].w;
adj[u].pb(make_pair(v, w));
adj[v].pb(make_pair(u, w));
}
FOR(i, 0, lg - 1){
st[i].init(n);
}
saveCenMax.init(n);
buildCentroid(1, 0);
FOR(i, 1, n) reCalc(i);
return;
}
void process()
{
preprocess();
ll last = 0;
FOR(i, 1, q){
ll dj = (Q[i].fi + last) % (n - 1) + 1;
ll ej = (Q[i].se + last) % W;
int u = E[dj].u, v = E[dj].v; ll w = E[dj].w;
updateCentroid(u, v, ej, w);
E[dj].w = ej;
cout << (last = saveCenMax.answer()) <<"\n";
}
return;
}
}
void solve()
{
cin >> n >> q >> W;
FOR(i, 1, n-1){
int a,b; ll c; cin >> a >> b >> c;
iE[i] = Edge(a, b, c);
}
FOR(i, 1, q){
cin >> Q[i].fi >> Q[i].se;
}
return Subtask6::process(), void();
if(Subtask12::checkSubtask()){
return Subtask12::process(), void();
}
if(Subtask3::checkSubtask()){
return Subtask3::process(), void();
}
if(Subtask4::checkSubtask()){
return Subtask4::process(), void();
}
return Subtask6::process(), void();
return Subtask5::process(), void();
}
signed main()
{
ios_base::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
#define name "InvMOD"
if(fopen(name".INP", "r")){
freopen(name".INP","r",stdin);
freopen(name".OUT","w",stdout);
}
int t = 1; //cin >> t;
while(t--) solve();
return 0;
}
Compilation message (stderr)
diameter.cpp: In function 'int main()':
diameter.cpp:648:16: warning: ignoring return value of 'FILE* freopen(const char*, const char*, FILE*)' declared with attribute 'warn_unused_result' [-Wunused-result]
648 | freopen(name".INP","r",stdin);
| ~~~~~~~^~~~~~~~~~~~~~~~~~~~~~
diameter.cpp:649:16: warning: ignoring return value of 'FILE* freopen(const char*, const char*, FILE*)' declared with attribute 'warn_unused_result' [-Wunused-result]
649 | freopen(name".OUT","w",stdout);
| ~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |