제출 #1125095

#제출 시각아이디문제언어결과실행 시간메모리
1125095InvMODDynamic Diameter (CEOI19_diameter)C++20
100 / 100
3183 ms233052 KiB
#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; }

컴파일 시 표준 에러 (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 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...