Submission #1352732

#TimeUsernameProblemLanguageResultExecution timeMemory
1352732cnam9Dynamic Diameter (CEOI19_diameter)C++20
0 / 100
1 ms580 KiB
#include <iostream>
#include <vector>
#define inline inline __attribute__((always_inline))

using namespace std;

constexpr int N = 1e5 + 5;

long long weights[N];
vector<pair<int, int>> tree[N];

enum class Type {
    Compress,
    Vertex,
    AddVertex,
    Rake,
    AddEdge
};

struct Node;

struct NodePtr {
    int id;

    inline NodePtr() { }
    inline NodePtr(int id) : id(id) { }
    inline NodePtr(nullptr_t ptr) : id(0) { }

    inline operator bool() const { return id != 0; }
    inline Node *operator->() const;
};

struct Node {
    NodePtr parent;
    NodePtr left, right;
    Type type;

    struct Data {
        long long d, du, dv, duv;

        inline void compress(const Data &left, const Data &right) {
            d = max(max(left.d, right.d), left.dv + right.du);
            du = max(left.du, left.duv + right.du);
            dv = max(right.dv, right.duv + left.dv);
            duv = left.duv + right.duv;
        }

        inline void add_vertex(const Data &child, int e) {
            duv = weights[e];
            dv = child.du;
            du = dv + weights[e];
            d = max(child.d, du);
        }

        void vertex(int e) {
            d = du = duv = weights[e];
            dv = 0;
        }

        inline void rake(const Data &left, const Data &right) {
            d = max(max(left.d, right.d), left.du + right.du);
            du = max(left.du, right.du);
        }

        inline void add_edge(const Data &child) {
            d = child.d;
            du = child.du;
        }

        friend ostream &operator<<(ostream &dest, const Data &data) {
            return dest << "Data(d=" << data.d << ", du=" << data.du << ", dv=" << data.dv << ", duv=" << data.duv << ")";
        }
    } data;

    inline void pull(int id) {
        switch (type)
        {
        case Type::Compress:
            data.compress(left->data, right->data);
            // cout << "hi Compress " << id << " data=" << data << endl;
            return;

        case Type::Vertex:
            data.vertex(id);
            // cout << "hi Vertex " << id << " data=" << data << endl;
            return;

        case Type::AddVertex:
            data.add_vertex(left->data, id);
            // cout << "hi AddVertex " << id << " data=" << data << endl;
            return;

        case Type::Rake:
            data.rake(left->data, right->data);
            // cout << "hi Rake " << id << " data=" << data << endl;
            return;

        case Type::AddEdge:
            data.add_edge(left->data);
            // cout << "hi AddEdge " << id << " data=" << data << endl;
            return;
        }
    }
};

Node pool[4 * N];
int num_nodes;

inline Node *NodePtr::operator->() const {
    return &pool[id];
}

inline NodePtr new_node(int id, NodePtr left, NodePtr right, Type type) {
    NodePtr node{id};
    left->parent = right->parent = node;
    node->left = left;
    node->right = right;
    node->type = type;
    return node;
}

int dfs(int u, int p) {
    int size = 1;
    int heavy_size = 0;

    for (int it = 0; it < tree[u].size(); ) {
        int v = tree[u][it].first;
        if (v == p) {
            swap(tree[u][it], tree[u].back());
            tree[u].pop_back();
            continue;
        }

        int child_size = dfs(v, u);
        if (child_size > heavy_size) {
            heavy_size = child_size;
            swap(tree[u][it], tree[u].front());
        }
        size += child_size;
        it++;
    }
    return size;
}

struct Cluster {
    NodePtr node;
    int size;
};

Cluster decompress(int, int);
Cluster remove_vertex(int, int);
Cluster split(int);
Cluster remove_edge(int, int);

template <Type type>
Cluster merge(vector<Cluster>::iterator first,
              vector<Cluster>::iterator last) {
    if (last - first == 1) return *first;

    int total_size = 0;
    for (auto it = first; it != last; ++it) {
        total_size += it->size;
    }

    auto mid = first;
    int left_size = 0;
    while (left_size * 2 + mid->size < total_size) {
        left_size += mid->size;
        ++mid;
    }

    NodePtr node = new_node(++num_nodes,
                            merge<type>(first, mid).node,
                            merge<type>(mid, last).node,
                            type);
    node->pull(0);
    return {node, total_size};
}

Cluster decompress(int u, int e) {
    int orig_u = u;
    vector<Cluster> children = {remove_vertex(u, e)};
    while (!tree[u].empty()) {
        int e = tree[u].front().second;
        u = tree[u].front().first;
        children.push_back(remove_vertex(u, e));
    }
    return merge<Type::Compress>(children.begin(), children.end());
}

inline Cluster remove_vertex(int u, int e) {
    auto [node, size] = split(u);
    node = new_node(e, node, nullptr, node ? Type::AddVertex : Type::Vertex);
    node->pull(e);
    return {node, size + 1};
}

inline Cluster split(int u) {
    vector<Cluster> children;
    for (int it = 1; it < tree[u].size(); it++) {
        children.push_back(remove_edge(tree[u][it].first, tree[u][it].second));
    }
    return children.empty() ? Cluster{nullptr, 0}
                            : merge<Type::Rake>(children.begin(), children.end());
}

inline Cluster remove_edge(int u, int e) {
    auto [node, size] = decompress(u, e);
    node = new_node(++num_nodes, node, nullptr, Type::AddEdge);
    node->pull(0);
    return {node, size};
}

NodePtr root;

inline void init(int n) {
    num_nodes = n - 1;

    dfs(1, 1);
    root = decompress(1, 0).node;
}

signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);

    // freopen("input.txt", "r", stdin);

    int n, q, W;
    cin >> n >> q >> W;

    for (int e = 1; e < n; e++) {
        int u, v;
        cin >> u >> v >> weights[e];

        tree[u].emplace_back(v, e);
        tree[v].emplace_back(u, e);
    }

    init(n);
    // cout << "dia = " << root->data.d << endl;

    long long last = 0;
    while (q--) {
        int e;
        long long w;
        cin >> e >> w;

        e = (e + last) % (n - 1) + 1;
        weights[e] = (w + last) % W;

        for (NodePtr node{e}; node; node = node->parent) {
            node->pull(node.id);
        }

        last = root->data.d;
        cout << last << '\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...