제출 #1258926

#제출 시각아이디문제언어결과실행 시간메모리
1258926herominhsteveMin-max tree (BOI18_minmaxtree)C++20
100 / 100
157 ms37844 KiB
#include <bits/stdc++.h>
using namespace std;

#define allof(x) (x).begin(), (x).end()
#define el '\n'

const int MAXN = 70005;
const int LOG = 17;
const int INF = 1e9+7;

// -------- input --------
struct Query {
    char type; // 'M' or 'm'
    int u, v, w;
};

// -------- tree / HLD --------
int n, K;
vector<int> g[MAXN];
int parent_[MAXN], depth_[MAXN], heavy[MAXN], head[MAXN], pos[MAXN], sz[MAXN];
int curPos;

int up_bin[MAXN][LOG+1]; // for optional LCA via binary lifting if needed

int edge_id_of_node[MAXN]; // edge index for edge(parent[u] -- u), 1..n-1 (0 for root)
int eu[MAXN], ev[MAXN];    // edges 1..n-1
int which_edge[MAXN][2];   // not used; placeholder if you want u->edge

// -------- queries --------
vector<Query> qs;          // 1..K (we'll index from 1)
unordered_map<int,int> qid_by_w; // map z -> query id (1..K)

// -------- events for sweep --------
vector<pair<int,int>> add_ev[MAXN], rem_ev[MAXN]; // (w, bit) bit=0 for min, 1 for max

// -------- edge bounds --------
int lo_edge[MAXN]; // max of active mins  on that edge
int up_edge[MAXN]; // min of active maxs  on that edge

// -------- matching graph: Left = queries (1..K), Right = edges (1..n-1) --------
vector<int> adjQ[MAXN]; // adj from query to candidate edges

// Hopcroft-Karp arrays
int distHK[MAXN], matchQ[MAXN], matchE[MAXN]; // matchQ[q] = edge, matchE[e] = query
queue<int> qHK;

int dfs_sz(int u, int p) {
    parent_[u] = p;
    depth_[u] = (p ? depth_[p] + 1 : 0);
    up_bin[u][0] = p;
    for (int k=1; k<=LOG; k++) up_bin[u][k] = up_bin[ up_bin[u][k-1] ][k-1];

    sz[u] = 1;
    int mx = 0;
    heavy[u] = 0;
    for (int v : g[u]) if (v != p) {
        int s = dfs_sz(v,u);
        sz[u] += s;
        if (s > mx) mx = s, heavy[u] = v;
    }
    return sz[u];
}

void decomp(int u, int h, int p, int &edge_counter) {
    head[u] = h;
    pos[u] = ++curPos;
    if (p) {
        edge_id_of_node[u] = ++edge_counter;
    } else {
        edge_id_of_node[u] = 0; // root has no parent edge
    }
    if (heavy[u]) decomp(heavy[u], h, u, edge_counter);
    for (int v : g[u]) if (v != p && v != heavy[u]) {
        decomp(v, v, u, edge_counter);
    }
}

int lca_hld(int a, int b) {
    while (head[a] != head[b]) {
        if (depth_[head[a]] > depth_[head[b]]) a = parent_[head[a]];
        else b = parent_[head[b]];
    }
    return depth_[a] < depth_[b] ? a : b;
}

inline void range_add_events(int L, int R, int w, int bit) {
    if (L > R) return;
    add_ev[L].push_back({w, bit});
    rem_ev[R].push_back({w, bit});
}

void add_path_events(int u, int v, int w, int bit) {
    while (head[u] != head[v]) {
        if (depth_[head[u]] >= depth_[head[v]]) {
            int top = head[u];
            // edges along nodes [pos[top] .. pos[u]], all covered except the parent of 'top'.
            range_add_events(pos[top], pos[u], w, bit);
            u = parent_[top];
        } else {
            int top = head[v];
            range_add_events(pos[top], pos[v], w, bit);
            v = parent_[top];
        }
    }
    if (depth_[u] < depth_[v]) swap(u, v); // ensure u is deeper
    if (u != v) {
        range_add_events(pos[v]+1, pos[u], w, bit);
    }
}

// ---------- Hopcroft–Karp ----------
bool bfs_HK(int K_left) {
    queue<int> q;
    for (int i=1;i<=K_left;i++){
        if (matchQ[i] == 0) distHK[i] = 0, q.push(i);
        else distHK[i] = -1;
    }
    bool reachable_free_edge = false;
    while (!q.empty()) {
        int u = q.front(); q.pop();
        for (int e : adjQ[u]) {
            int v = matchE[e];
            if (v == 0) {
                reachable_free_edge = true;
            } else if (distHK[v] == -1) {
                distHK[v] = distHK[u] + 1;
                q.push(v);
            }
        }
    }
    return reachable_free_edge;
}

bool dfs_HK(int u) {
    for (int e : adjQ[u]) {
        int v = matchE[e];
        if (v == 0 || (distHK[v] == distHK[u] + 1 && dfs_HK(v))) {
            matchQ[u] = e;
            matchE[e] = u;
            return true;
        }
    }
    distHK[u] = -1;
    return false;
}

int hopcroft_karp(int K_left, int E_right) {
    for (int i=1;i<=K_left;i++) matchQ[i] = 0;
    for (int e=1;e<=E_right;e++) matchE[e] = 0;
    int matching = 0;
    while (bfs_HK(K_left)) {
        for (int i=1;i<=K_left;i++) {
            if (matchQ[i] == 0) {
                if (dfs_HK(i)) matching++;
            }
        }
    }
    return matching;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    cin >> n;
    for (int i=1;i<n;i++) {
        int u,v; cin >> u >> v;
        g[u].push_back(v);
        g[v].push_back(u);
        eu[i] = u; ev[i] = v;
    }
    cin >> K;
    qs.resize(K+1);
    for (int i=1;i<=K;i++) {
        char t; int u,v,w;
        cin >> t >> u >> v >> w;
        qs[i] = {t,u,v,w};
        qid_by_w[w] = i;
    }

    dfs_sz(1,0);
    int edge_counter = 0;
    decomp(1,1,0,edge_counter);
    for (int i=1;i<=K;i++) {
        int u = qs[i].u, v = qs[i].v, w = qs[i].w;
        int bit = (qs[i].type == 'M') ? 1 : 0; // 0=min, 1=max
        add_path_events(u, v, w, bit);
    }

    for (int e=1;e<=n-1;e++) lo_edge[e] = -INF, up_edge[e] = INF;

    multiset<int> activeMin, activeMax;
    for (int p=1;p<=n;p++) {
        for (auto pr : add_ev[p]) {
            int w = pr.first, bit = pr.second;
            if (bit == 0) activeMin.insert(w);
            else activeMax.insert(w);
        }

        int u = 0;
        static bool built_inv = false;
        static int invPos[MAXN];
        if (!built_inv) {
            for (int v=1; v<=n; v++) invPos[pos[v]] = v;
            built_inv = true;
        }
        u = invPos[p];

        int e = edge_id_of_node[u];
        if (e) {
            if (!activeMin.empty()) lo_edge[e] = max(lo_edge[e], *activeMin.rbegin());
            if (!activeMax.empty()) up_edge[e] = min(up_edge[e], *activeMax.begin());
        }

        for (auto pr : rem_ev[p]) {
            int w = pr.first, bit = pr.second;
            if (bit == 0) {
                auto it = activeMin.find(w);
                if (it != activeMin.end()) activeMin.erase(it);
            } else {
                auto it = activeMax.find(w);
                if (it != activeMax.end()) activeMax.erase(it);
            }
        }
    }

    for (int e=1;e<=n-1;e++) {
        if (lo_edge[e] != -INF) {
            auto it = qid_by_w.find(lo_edge[e]);
            if (it != qid_by_w.end()) {
                adjQ[it->second].push_back(e);
            }
        }
        if (up_edge[e] != INF && up_edge[e] != lo_edge[e]) {
            auto it = qid_by_w.find(up_edge[e]);
            if (it != qid_by_w.end()) {
                adjQ[it->second].push_back(e);
            }
        }
    }

    int Msize = hopcroft_karp(K, n-1);

    vector<int> ans(n); 
    for (int e=1;e<=n-1;e++) {
        int val = 0;
        if (lo_edge[e] != -INF) val = lo_edge[e];
        if (up_edge[e] != INF) val = min(val, up_edge[e]); 
        ans[e] = val;
    }

    for (int q=1;q<=K;q++) {
        int e = matchQ[q];
        if (e) ans[e] = qs[q].w;
    }

    unordered_map<long long,int> mapEdge;
    mapEdge.reserve(n*2);
    auto keyOf = [&](int a, int b)->long long {
        if (a>b) swap(a,b);
        return ( (long long)a << 32 ) ^ (long long)b;
    };
    for (int u=2; u<=n; u++) {
        int p = parent_[u];
        int e = edge_id_of_node[u];
        mapEdge[keyOf(p,u)] = e;
    }

    // Print in the original input order
    for (int i=1;i<=n-1;i++) {
        int u = eu[i], v = ev[i];
        int e = mapEdge[keyOf(u,v)];
        cout << u << ' ' << v << ' ' << ans[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...