제출 #703174

#제출 시각아이디문제언어결과실행 시간메모리
703174CyanmondDynamic Diameter (CEOI19_diameter)C++17
100 / 100
4722 ms169868 KiB
#pragma GCC target("avx2")
#pragma GCC optimize("O3")

#include <bits/stdc++.h>

using i64 = long long;
struct Edge {
    int to;
    i64 w;
};

using T = std::pair<i64, int>;
T op(const T& a, const T& b) {
    return std::max(a, b);
}
T e() {
    return {0, 0};
}
using U = i64;
T map(i64 a, const T& b) {
    return {b.first + a, b.second};
}
i64 composite(i64 a, i64 b) {
    return a + b;
}
i64 id() {
    return 0;
}

class lazySegtree {
    int n, logn, size;
    std::vector<T> node;
    std::vector<U> lazy;

    void update(int i) {
        node[i] = op(node[2 * i], node[2 * i + 1]);
    }

    void all_apply(int i, U f) {
        node[i] = map(f, node[i]);
        if (i < size) lazy[i] = composite(f, lazy[i]);
    }

    void push(int i) {
        all_apply(2 * i, lazy[i]);
        all_apply(2 * i + 1, lazy[i]);
        lazy[i] = id();
    }

    public:
    lazySegtree() {}

    lazySegtree(std::vector<T> initVec) {
        n = (int)initVec.size();
        logn = 0;
        while ((1 << logn) < n) {
            ++logn;
        }
        size = 1 << logn;
        node.assign(2 * size, e());
        lazy.assign(size, id());
        std::copy(initVec.begin(), initVec.end(), node.begin() + size);
        for (int i = size - 1; i >= 1; --i) {
            update(i);
        }
    }

    void apply(int l, int r, U f) {
        l += size, r += size;
        for (int d = logn; d >= 1; --d) {
            if (((l >> d) << d) != l) push(l >> d);
            if (((r >> d) << d) != r) push((r - 1) >> d);
        }
        int l2 = l, r2 = r;
        while (l < r) {
            if (l & 1) all_apply(l++, f);
            if (r & 1) all_apply(--r, f);
            l /= 2;
            r /= 2;
        }
        l = l2, r = r2;
        for (int d = 1; d <= logn; ++d) {
            if (((l >> d) << d) != l) update(l >> d);
            if (((r >> d) << d) != r) update((r - 1) >> d);
        }
    }

    T fold(int l, int r) {
        l += size, r += size;
        for (int d = logn; d >= 1; --d) {
            if (((l >> d) << d) != l) push(l >> d);
            if (((r >> d) << d) != r) push((r - 1) >> d);
        }
        T pl = e(), pr = e();
        while (l < r) {
            if (l & 1) pl = op(pl, node[l++]);
            if (r & 1) pr = op(node[--r], pr);
            l /= 2;
            r /= 2;
        }
        return op(pl, pr);
    }
};

std::vector<std::vector<Edge>> tree;

struct TreeManager {
    int n;
    std::vector<char> isOn, isCentroid;
    std::vector<int> size, in, out, fe, cen;
    std::vector<int> revIn;
    std::vector<i64> depth;

    TreeManager() {}

    TreeManager(const std::vector<char> &ison, const std::vector<int> &roots) {
        isOn = ison;
        n = tree.size();
        isCentroid.assign(n, false);
        size.assign(n, -1);
        in.assign(n, -1);
        out.assign(n, -1);
        depth.assign(n, 0);
        fe.assign(n, 0);
        cen.assign(n, 0);
        int id = 0;
        for (const int v : roots) {
            dfs1(v, -1);
            int x = findCentroid(v, -1, size[v]);
            dfs2(x, -1, id, 0, -1, x);
        }
        revIn.resize(n);
        for (int i = 0; i < n; ++i) {
            if (in[i] >= 0) {
                revIn[in[i]] = i;
            }
        }
    }

    void dfs1(int v, int p) {
        size[v] = 1;
        for (const auto &[t, w] : tree[v]) {
            if (t == p or (not isOn[t])) {
                continue;
            }
            dfs1(t, v);
            size[v] += size[t];
        }
    }

    int findCentroid(int v, int p, int as) {
        bool isCent = true;
        for (const auto &[t, w] : tree[v]) {
            if (t == p or (not isOn[t])) {
                continue;
            }
            int res = findCentroid(t, v, as);
            if (res != -1) {
                return res;
            }
            if (size[t] > as / 2) {
                isCent = false;
            }
        }
        if ((as - size[v]) > as / 2) {
            isCent = false;
        }
        isCentroid[v] = isCent;
        return isCent ? v : -1;
    }

    void dfs2(int v, int p, int &id, i64 d, int f, int ce) {
        fe[v] = f;
        in[v] = id++;
        cen[v] = ce;
        depth[v] = d;
        size[v] = 1;
        for (const auto &[t, w] : tree[v]) {
            if (t == p or (not isOn[t])) {
                continue;
            }
            dfs2(t, v, id, d + w, (f == -1 ? t : f), ce);
            size[v] += size[t];
        }
        out[v] = id;
    }
};

int main() {
    int N, Q;
    i64 W;
    std::cin >> N >> Q >> W;
    std::vector<int> A(N - 1), B(N - 1);
    std::vector<i64> C(N - 1);
    tree.resize(N);
    for (int i = 0; i < N - 1; ++i) {
        std::cin >> A[i] >> B[i] >> C[i];
        --A[i], --B[i];
        tree[A[i]].push_back({B[i], C[i]});
        tree[B[i]].push_back({A[i], C[i]});
    }

    std::vector<char> isOn(N, true);
    std::vector<int> roots = {0};
    std::vector<TreeManager> managers;
    while (true) {
        TreeManager mng(isOn, roots);
        roots.clear();
        for (int i = 0; i < N; ++i) {
            if (not mng.isCentroid[i]) {
                continue;
            }
            isOn[i] = false;
            for (const auto &[t, w] : tree[i]) {
                if (not isOn[t]) {
                    continue;
                }
                roots.push_back(t);
            }
        }
        managers.push_back(std::move(mng));
        if (std::none_of(isOn.begin(), isOn.end(), [](bool b) {
            return b;
        })) {
            break;
        }
    }
    const int m = (int)managers.size();
    std::vector<lazySegtree> segs(m);
    std::multiset<i64> diameters;
    std::vector<i64> memoDiameters(N);
    for (int x = 0; x < m; ++x) {
        auto &mng = managers[x];
        std::vector<std::pair<i64, int>> weighVec(N);
        for (int i = 0; i < N; ++i) {
            if (mng.in[i] == -1) {
                continue;
            }
            weighVec[mng.in[i]].first = mng.depth[i];
        }
        for (int i = 0; i < N; ++i) {
            weighVec[i].second = i;
        }
        segs[x] = lazySegtree(weighVec);

        for (int i = 0; i < N; ++i) {
            if (not mng.isCentroid[i]) {
                continue;
            }
            if (mng.size[i] == 1) {
                continue;
            }
            const int bl = mng.in[i], br = mng.out[i];
            const auto [v, p] = segs[x].fold(bl, br);
            const int l = mng.in[mng.fe[mng.revIn[p]]], r = mng.out[mng.fe[mng.revIn[p]]];
            const auto v2 = std::max(segs[x].fold(bl, l).first, segs[x].fold(r, br).first);
            diameters.insert(v + v2);
            memoDiameters[i] = v + v2;
        }
    }

    i64 last = 0;
    while (Q--) {
        int d;
        i64 e;
        std::cin >> d >> e;
        i64 i = (last + d) % (N - 1);
        i64 w = (last + e) % W;
        int a = A[i], b = B[i];
        for (int x = 0; x < m; ++x) {
            auto &mng = managers[x];
            if ((not mng.isOn[a]) or (not mng.isOn[b])) {
                break;
            }
            if (mng.depth[a] > mng.depth[b]) {
                std::swap(a, b);
            }
            const int c = mng.cen[a];
            if (mng.size[c] == 1) {
                break;
            }
            diameters.erase(diameters.find(memoDiameters[c]));
            segs[x].apply(mng.in[b], mng.out[b], (w - C[i]));
            const int bl = mng.in[c], br = mng.out[c];
            const auto [v3, p3] = segs[x].fold(bl, br);
            const int l = mng.in[mng.fe[mng.revIn[p3]]], r = mng.out[mng.fe[mng.revIn[p3]]];
            const auto v2 = std::max(segs[x].fold(bl, l).first, segs[x].fold(r, br).first);
            diameters.insert(v3 + v2);
            memoDiameters[c] = v3 + v2;
        }
        C[i] = w;
        last = *diameters.rbegin();
        std::cout << last << std::endl;
    }
}
#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...