제출 #1259285

#제출 시각아이디문제언어결과실행 시간메모리
1259285herominhsteveMin-max tree (BOI18_minmaxtree)C++20
100 / 100
161 ms31576 KiB
#include <bits/stdc++.h> using namespace std; #define el '\n' const int MAXN = 70005; const int NEG_INF = -1000000000; const int INF = 1000000000; struct Query { bool type; // 1 for 'M' (max), 0 for 'm' (min) int u, v; int w; Query(char x='#', int U=0, int V=0, int W=0) { type = (x == 'M' ? 1 : 0); u = U; v = V; w = W; } }; int n, q; vector<int> graph[MAXN]; vector<Query> queryv; // 1..q int uID[MAXN], vID[MAXN]; // original edges in input order // ------------ Hopcroft-Karp (kept your structure) -------------- struct Hopcorft { int nL, nR; vector<vector<int>> graph; // adjacency left -> list of right indices vector<int> matchLeft, matchRight; vector<int> distancia; Hopcorft(int l = 0, int r = 0) { init(l,r); } void init(int l, int r) { nL = l; nR = r; graph.assign(nL+1, {}); matchLeft.assign(nL+1, 0); matchRight.assign(nR+1, 0); distancia.assign(nL+1, 0); } void addEdge(int u, int v) { // u in [1..nL], v in [1..nR] if (u<=0 || v<=0) return; graph[u].push_back(v); } bool bfs() { queue<int> qu; for (int u=1; u<=nL; ++u) { if (!matchLeft[u]) { distancia[u] = 0; qu.push(u); } else distancia[u] = INF; } distancia[0] = INF; while (!qu.empty()) { int u = qu.front(); qu.pop(); if (distancia[u] >= distancia[0]) continue; for (int v : graph[u]) { int paired = matchRight[v]; // left index matched to v or 0 if (distancia[paired] == INF) { distancia[paired] = distancia[u] + 1; qu.push(paired); } } } return (distancia[0] != INF); } bool dfs(int u) { if (!u) return true; for (int v : graph[u]) { if (distancia[ matchRight[v] ] == distancia[u] + 1 && dfs(matchRight[v])) { matchRight[v] = u; matchLeft[u] = v; return true; } } distancia[u] = INF; return false; } int maxMatching() { int match = 0; while (bfs()) { for (int u=1; u<=nL; ++u) if (!matchLeft[u] && dfs(u)) match++; } return match; } // write matched query weights into res[edge_id] void getW(vector<int> &res) { maxMatching(); for (int u=1; u<=nL; ++u) { if (matchLeft[u]) { int e = matchLeft[u]; // matched edge id (right side) res[e] = queryv[u].w; // query index u matched to edge e } } } }; // ---------- events for sweepline (store w,type,id) ---------- struct Ev { int w; int type; int id; }; vector<Ev> eventA[MAXN], eventR[MAXN]; // index by HLD position inline void rangeAddEvent(int l, int r, int w, int type, int id) { if (l > r) return; eventA[l].push_back({w,type,id}); eventR[r].push_back({w,type,id}); } // ----------------- HLD ----------------- int timedfs = 1, curChain = 1, edgecnt = 0; int eID[MAXN]; // eID[u] = edge id for parent[u]-u (0 for root) int parentArr[MAXN]; int pos[MAXN], arrPos[MAXN]; namespace HeavyLight { vector<int> chainHead, chainID; vector<int> depth, sz; void dfs(int u, int pre) { parentArr[u] = pre; for (int v : graph[u]) if (v != pre) { depth[v] = depth[u] + 1; dfs(v,u); sz[u] += sz[v]; } } void HLD(int u, int pre) { if (!chainHead[curChain]) chainHead[curChain] = u; chainID[u] = curChain; pos[u] = timedfs; arrPos[timedfs] = u; timedfs++; if (u == pre) eID[u] = 0; // root sentinel (we keep parent[root]=root) else eID[u] = ++edgecnt; int nxt = -1; for (int v : graph[u]) if (v != pre) { if (nxt == -1 || sz[v] > sz[nxt]) nxt = v; } if (nxt != -1) HLD(nxt, u); for (int v : graph[u]) if (v != pre && v != nxt) { curChain++; HLD(v, u); } } // add path events using positions void addEvent(int u, int v, int w, int type, int id) { while (chainHead[chainID[u]] != chainHead[chainID[v]]) { if (depth[chainHead[chainID[u]]] < depth[chainHead[chainID[v]]]) swap(u,v); int L = pos[ chainHead[ chainID[u] ] ]; int R = pos[u]; rangeAddEvent(L, R, w, type, id); u = parentArr[ chainHead[ chainID[u] ] ]; } if (depth[u] < depth[v]) swap(u,v); if (u != v) { // we need edges under v..u, which map to positions pos[v]+1 .. pos[u] rangeAddEvent(pos[v] + 1, pos[u], w, type, id); } } void initHLD() { chainHead.assign(n+2, 0); chainID.assign(n+2, 0); depth.assign(n+2, 0); sz.assign(n+2, 1); // keep parent[root]=root sentinel dfs(1, 1); HLD(1, 1); } } using namespace HeavyLight; // ---------------- input ---------------- void readInput() { ios::sync_with_stdio(false); cin.tie(nullptr); cin >> n; for (int i=1;i<n;i++){ int u,v; cin >> u >> v; graph[u].push_back(v); graph[v].push_back(u); uID[i] = u; vID[i] = v; } cin >> q; queryv.resize(q+1); for (int i=1;i<=q;i++){ char c; int u,v,w; cin >> c >> u >> v >> w; queryv[i] = Query(c,u,v,w); } } // ---------------- solve ---------------- int main(){ readInput(); initHLD(); // build events (use query index as id) for (int i=1;i<=q;i++){ addEvent(queryv[i].u, queryv[i].v, queryv[i].w, queryv[i].type, i); } // per-edge info vector<int> loVal(edgecnt+1, NEG_INF), hiVal(edgecnt+1, INF); vector<int> loId(edgecnt+1, 0), hiId(edgecnt+1, 0); // active sets store (w,id) multiset<pair<int,int>> activeMin, activeMax; // sweep positions 1..n for (int cur = 1; cur <= n; ++cur) { // add events starting here for (auto &ev : eventA[cur]) { if (ev.type) activeMax.insert({ev.w, ev.id}); // M queries -> activeMax else activeMin.insert({ev.w, ev.id}); // m queries -> activeMin } int u = arrPos[cur]; int e = eID[u]; // if 0 skip (root) if (e) { if (!activeMax.empty()) { auto it = activeMax.begin(); // smallest max constraint if (it->first < hiVal[e]) { hiVal[e] = it->first; hiId[e] = it->second; } } if (!activeMin.empty()) { auto it = prev(activeMin.end()); // largest min constraint if (it->first > loVal[e]) { loVal[e] = it->first; loId[e] = it->second; } } } // remove events ending here for (auto &ev : eventR[cur]) { if (ev.type) { auto it = activeMax.find({ev.w, ev.id}); if (it != activeMax.end()) activeMax.erase(it); } else { auto it = activeMin.find({ev.w, ev.id}); if (it != activeMin.end()) activeMin.erase(it); } } } // Build matching graph: Left = queries 1..q, Right = edges 1..edgecnt Hopcorft karp(q, edgecnt); for (int e=1; e<=edgecnt; ++e) { if (loId[e]) karp.addEdge(loId[e], e); if (hiId[e] && hiId[e] != loId[e]) karp.addEdge(hiId[e], e); } // default assign per-edge value within [loVal, hiVal] vector<int> res(edgecnt+1, 0); for (int e=1;e<=edgecnt;++e) { int val = 0; if (loVal[e] != NEG_INF) val = max(val, loVal[e]); if (hiVal[e] != INF) val = min(val, hiVal[e]); // if inconsistent (lo > hi), we still put something; judge problem usually guarantees feasibility res[e] = val; } // run matching and overwrite matched edges with exact query w karp.getW(res); // map edges to input order: normalize endpoints auto norm = [](int a,int b)->pair<int,int>{ if (a>b) swap(a,b); return {a,b}; }; unordered_map<long long,int> toEID; toEID.reserve(edgecnt*2); auto key = [](int a,int b)->long long { if (a>b) swap(a,b); return ( (long long)a<<32 ) ^ (long long)b; }; for (int v=2; v<=n; ++v) { int u = parentArr[v]; toEID[key(u,v)] = eID[v]; } // print in the original input order for (int i=1;i<n;i++){ int a = uID[i], b = vID[i]; int e = toEID[key(a,b)]; cout << a << ' ' << b << ' ' << res[e] << el; } 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...