제출 #1333140

#제출 시각아이디문제언어결과실행 시간메모리
1333140mamabearWind Turbines (EGOI25_windturbines)C++20
0 / 100
2447 ms51572 KiB
#include <iostream>
#include <vector>
#include <algorithm>
#include <cmath>

using namespace std;

struct Edge {
    int u, v;
    long long c;
    bool operator<(const Edge& o) const {
        return c < o.c;
    }
};

struct Query {
    int l, r, id;
};

const int MAX_NODES = 200005;

int parent_dsu[MAX_NODES];
int find_set(int v) {
    if (v == parent_dsu[v]) return v;
    return parent_dsu[v] = find_set(parent_dsu[v]);
}

vector<int> adj[MAX_NODES];
long long W[MAX_NODES];
int pos_in_dfs[MAX_NODES];
vector<int> leaf_order;

int euler[MAX_NODES * 2];
int euler_depth[MAX_NODES * 2];
int first_occ[MAX_NODES];
int timer_dfs = 0;

void dfs(int u, int d) {
    first_occ[u] = timer_dfs;
    euler[timer_dfs] = u;
    euler_depth[timer_dfs] = d;
    timer_dfs++;

    if (u < (MAX_NODES / 2)) {
        pos_in_dfs[u] = leaf_order.size();
        leaf_order.push_back(u);
    }

    for (int v : adj[u]) {
        dfs(v, d + 1);
        euler[timer_dfs] = u;
        euler_depth[timer_dfs] = d;
        timer_dfs++;
    }
}

int st[20][MAX_NODES * 2];
int lg[MAX_NODES * 2];

void build_sparse_table(int m) {
    lg[1] = 0;
    for (int i = 2; i <= m; i++) lg[i] = lg[i / 2] + 1;
    for (int i = 0; i < m; i++) st[0][i] = i;
    for (int j = 1; (1 << j) <= m; j++) {
        for (int i = 0; i + (1 << j) <= m; i++) {
            int left = st[j - 1][i];
            int right = st[j - 1][i + (1 << (j - 1))];
            st[j][i] = (euler_depth[left] < euler_depth[right]) ? left : right;
        }
    }
}

int query_lca(int u, int v) {
    int l = first_occ[u];
    int r = first_occ[v];
    if (l > r) swap(l, r);
    int j = lg[r - l + 1];
    int left = st[j][l];
    int right = st[j][r - (1 << j) + 1];
    return (euler_depth[left] < euler_depth[right]) ? euler[left] : euler[right];
}

int prev_node[MAX_NODES];
int next_node[MAX_NODES];
long long current_dropped = 0;

struct State {
    int v, p, n;
    long long dropped;
};
vector<State> history;

void delete_node(int v, bool save) {
    int p = prev_node[v];
    int n = next_node[v];
    
    if (save) {
        history.push_back({v, p, n, current_dropped});
    }

    if (p != -1) current_dropped -= W[query_lca(p, v)];
    if (n != -1) current_dropped -= W[query_lca(v, n)];
    if (p != -1 && n != -1) current_dropped += W[query_lca(p, n)];

    if (p != -1) next_node[p] = n;
    if (n != -1) prev_node[n] = p;
}

void undo() {
    State s = history.back();
    history.pop_back();
    current_dropped = s.dropped;
    if (s.p != -1) next_node[s.p] = s.v;
    if (s.n != -1) prev_node[s.n] = s.v;
}

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);

    int N, M, Q;
    if (!(cin >> N >> M >> Q)) return 0;

    vector<Edge> edges(M);
    for (int i = 0; i < M; i++) {
        cin >> edges[i].u >> edges[i].v >> edges[i].c;
    }

    sort(edges.begin(), edges.end());

    for (int i = 0; i < 2 * N; i++) {
        parent_dsu[i] = i;
        W[i] = 0;
    }

    long long W_MST = 0;
    int node_idx = N;

    for (int i = 0; i < M; i++) {
        int pu = find_set(edges[i].u);
        int pv = find_set(edges[i].v);
        if (pu != pv) {
            parent_dsu[pu] = node_idx;
            parent_dsu[pv] = node_idx;
            W[node_idx] = edges[i].c;
            W_MST += edges[i].c;
            adj[node_idx].push_back(pu);
            adj[node_idx].push_back(pv);
            node_idx++;
        }
    }

    int root = node_idx - 1;
    dfs(root, 0);
    build_sparse_table(timer_dfs);

    vector<Query> queries(Q);
    for (int i = 0; i < Q; i++) {
        cin >> queries[i].l >> queries[i].r;
        queries[i].id = i;
    }

    int B = max(1, (int)(N / sqrt(Q)));
    sort(queries.begin(), queries.end(), [&](const Query& a, const Query& b) {
        int b_a = a.l / B;
        int b_b = b.l / B;
        if (b_a != b_b) return b_a < b_b;
        return a.r > b.r;
    });

    vector<long long> ans(Q);
    int num_blocks = (N / B) + 1;
    int q_idx = 0;

    for (int b = 0; b < num_blocks && q_idx < Q; b++) {
        int block_start = b * B;
        if (queries[q_idx].l / B != b) continue;

        int last = -1;
        current_dropped = 0;
        for (int u : leaf_order) {
            if (u >= block_start) {
                if (last != -1) {
                    next_node[last] = u;
                    prev_node[u] = last;
                    current_dropped += W[query_lca(last, u)];
                } else {
                    prev_node[u] = -1;
                }
                last = u;
            }
        }
        if (last != -1) next_node[last] = -1;

        int curr_R = N - 1;

        while (q_idx < Q && queries[q_idx].l / B == b) {
            int L = queries[q_idx].l;
            int R = queries[q_idx].r;
            int id = queries[q_idx].id;

            while (curr_R > R) {
                delete_node(curr_R, false);
                curr_R--;
            }

            int saves = 0;
            for (int x = block_start; x < L; x++) {
                delete_node(x, true);
                saves++;
            }

            ans[id] = W_MST - current_dropped;

            for (int i = 0; i < saves; i++) undo();

            q_idx++;
        }
    }

    for (int i = 0; i < Q; i++) cout << ans[i] << "\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...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...