Submission #954112

#TimeUsernameProblemLanguageResultExecution timeMemory
954112LucaIlieDynamic Diameter (CEOI19_diameter)C++17
31 / 100
5032 ms283548 KiB
#include <bits/stdc++.h> #define pragma "ofast" using namespace std; struct edge { int u, v; long long w; int other( int x ) { return u ^ v ^ x; } }; const int MAX_N = 1e5; edge edges[MAX_N]; vector<int> adj[MAX_N + 1]; bool isCentroid[MAX_N + 1]; int sz[MAX_N + 1]; void calcSizes( int u, int p ) { sz[u] = 1; for ( int e: adj[u] ) { int v = edges[e].other( u ); if ( v == p || isCentroid[v] ) continue; calcSizes( v, u ); sz[u] += sz[v]; } } int totSz; int findCentroid( int u, int p ) { int c = 0, maxSz = totSz - sz[u]; for ( int e: adj[u] ) { int v = edges[e].other( u ); if ( v == p || isCentroid[v] ) continue; int d = findCentroid( v, u ); if ( d != 0 ) c = d; maxSz = max( maxSz, sz[v] ); } if ( maxSz <= totSz / 2 ) c = u; return c; } vector<int> centroids[MAX_N], heads[MAX_N + 1]; unordered_map<int, int> head[MAX_N + 1], leftPos[MAX_N + 1], rightPos[MAX_N + 1]; int crtPos; void dfs( int u, int p, int c, int h ) { int children = 0; for ( int e: adj[u] ) { int v = edges[e].other( u ); if ( v == p || isCentroid[v] ) continue; centroids[e].push_back( c ); head[c][e] = h; leftPos[c][e] = crtPos; dfs( v, u, c, h ); rightPos[c][e] = crtPos - 1; children++; } if ( children == 0 ) crtPos++; } void decomp( int r ) { calcSizes( r, 0 ); totSz = sz[r]; int c = findCentroid( r, 0 ); for ( int e: adj[c] ) { int v = edges[e].other( c ); if ( isCentroid[v] ) continue; centroids[e].push_back( c ); heads[c].push_back( e ); head[c][e] = e; leftPos[c][e] = crtPos; dfs( v, c, c, e ); rightPos[c][e] = crtPos - 1; } isCentroid[c] = true; for ( int e: adj[c] ) { int v = edges[e].other( c ); if ( isCentroid[v] ) continue; decomp( v ); } } multiset<int> diameterByCentroid[MAX_N + 1], allDiameters; struct SegTree { int ll, rr; vector<long long> segTree, lazy; void propag( int v, int l, int r ) { segTree[v] += lazy[v]; if ( l != r ) { lazy[v * 2 + 1] += lazy[v]; lazy[v * 2 + 2] += lazy[v]; } lazy[v] = 0; } void init( int l, int r ) { ll = l; rr = r; segTree.resize( 4 * (r - l + 1) ); lazy.resize( 4 * (r - l + 1) ); } void update( int v, int l, int r, int lu, int ru, long long x ) { propag( v, l, r ); if ( l > ru || r < lu ) return; if ( lu <= l && r <= ru ) { lazy[v] = x; propag( v, l, r ); return; } int mid = (l + r) / 2; update( v * 2 + 1, l, mid, lu, ru, x ); update( v * 2 + 2, mid + 1, r, lu, ru, x ); segTree[v] = max( segTree[v * 2 + 1], segTree[v * 2 + 2] ); } void update( int l, int r, long long x ) { update( 0, ll, rr, l, r, x ); } long long query( int v, int l, int r, int lq, int rq ) { if ( l > rq || r < lq ) return 0; if ( lq <= l && r <= rq ) return segTree[v]; int mid = (l + r) / 2; return max( query( v * 2 + 1, l, mid, lq, rq ), query( v * 2 + 2, mid + 1, r, lq, rq ) ); } long long query( int l, int r ) { return query( 0, ll, rr, l, r ); } } depths; int main() { int n, q; long long m; cin >> n >> q >> m; for ( int e = 0; e < n - 1; e++ ) { cin >> edges[e].u >> edges[e].v >> edges[e].w; adj[edges[e].u].push_back( e ); adj[edges[e].v].push_back( e ); } crtPos = 0; decomp( 1 ); depths.init( 0, crtPos - 1 ); for ( int c = 1; c <= n; c++ ) { for ( auto p: head[c] ) { int e = p.first; depths.update( leftPos[c][e], rightPos[c][e], edges[e].w ); } for ( int h: heads[c] ) { int maxDepth = depths.query( leftPos[c][h], rightPos[c][h] ); diameterByCentroid[c].insert( maxDepth ); } int d1 = (diameterByCentroid[c].size() <= 0 ? 0 : *diameterByCentroid[c].rbegin()); int d2 = (diameterByCentroid[c].size() <= 1 ? 0 : *next( diameterByCentroid[c].rbegin() ) ); allDiameters.insert( d1 + d2 ); } int last = 0; while ( q-- ) { int e; long long w; cin >> e >> w; e = (e + last) % (n - 1); w = (w + last) % m; for ( int c: centroids[e] ) { int d1, d2, maxDepth; d1 = (diameterByCentroid[c].size() <= 0 ? 0 : *diameterByCentroid[c].rbegin()); d2 = (diameterByCentroid[c].size() <= 1 ? 0 : *next( diameterByCentroid[c].rbegin() ) ); allDiameters.erase( allDiameters.lower_bound( d1 + d2 ) ); int h = head[c][e]; maxDepth = depths.query( leftPos[c][h], rightPos[c][h] ); diameterByCentroid[c].erase( diameterByCentroid[c].lower_bound( maxDepth ) ); depths.update( leftPos[c][e], rightPos[c][e], w - edges[e].w ); maxDepth = depths.query( leftPos[c][h], rightPos[c][h] ); diameterByCentroid[c].insert( maxDepth ); d1 = (diameterByCentroid[c].size() <= 0 ? 0 : *diameterByCentroid[c].rbegin()); d2 = (diameterByCentroid[c].size() <= 1 ? 0 : *next( diameterByCentroid[c].rbegin() ) ); allDiameters.insert( d1 + d2 ); } edges[e].w = w; last = *allDiameters.rbegin(); 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...