Submission #198111

#TimeUsernameProblemLanguageResultExecution timeMemory
198111model_codeDynamic Diameter (CEOI19_diameter)C++17
49 / 100
5028 ms162020 KiB
#include <vector>
#include <stack>
#include <iostream>
#include <unordered_map>
#include <unordered_set>
#include <map>
#include <iomanip>
#include <set>
#include <functional>
#include <fstream>
#include <algorithm>
#include <queue>
using namespace std;

#define x first
#define y second
typedef std::pair<int, int> pii;
typedef long long ll;
typedef unsigned long long ull;
typedef unsigned int ui;
typedef pair<ui, ui> puu;

template<typename T> using minheap = priority_queue<T, vector<T>, greater<T>>;
template<typename T> using maxheap = priority_queue<T, vector<T>, less<T>>;

ui logceil(ll x) { return x ? 8 * sizeof(ll) - __builtin_clzll(x) : 0; }

namespace std {
template<typename T, typename U>struct hash<pair<T, U>> {
        hash<T>t;
        hash<U>u;
        size_t operator()(const pair<T, U>&p)const {
                return t(p.x) ^ (u(p.y) << 7);
        }
};
}


template <typename EdgeType>
class DFSOrder {
public:
        DFSOrder(const vector<vector<EdgeType>> &_E) : T(0), N(_E.size()), E(_E), RevEnter(N), Enter(N), Exit(N) {
                dfs(0, -1);
        }

        vector<vector<EdgeType>> linearize() {
                vector<vector<EdgeType>> F(N);
                for (int i = 0; i < N; ++i) {
                        for (auto v : E[i]) {
                                F[conv(i)].push_back(conv(v));
                        }
                }
                return F;
        }

        void dfs(int u, int p) {
                RevEnter[T] = u;
                Enter[u] = T++;
                for (auto v : E[u]) if (t(v) != p) dfs(t(v), u);
                Exit[u] = T;
        }

        inline int t(const int&e) const {
                return e;
        }
        template <typename U> inline int t(const pair<int, U>&e) const {
                return e.x;
        }

        inline int conv(const int&e) const {
                return Enter[e];
        }
        template <typename U> inline pair<int, U> conv(const pair<int, U>&e) const {
                return {Enter[e.x], e.y};
        }

        const vector<int> &revEnter() const {
                return RevEnter;
        }
        const vector<int> &enter() const {
                return Enter;
        }
        const vector<int> &exit() const {
                return Exit;
        }

        int T, N;
        const vector<vector<EdgeType>> &E;
        vector<int> Enter, Exit, RevEnter;
};

/** Centroid decomposition.
 *
 * Input: graph as adjacency list (either int or pair<int,T>)
 * Output: array U of integers of size |V|
 *
 * Here, U[v] is the bfs order in the centroid tree. For DFS, only process
 * vertices with higher U[w] when processing centroid v, for instance:
 *
 * void dfs(int u, int p, int ctr, ...) {
 *      ....
 *      for (int v:E[u]) {
 *          if (v != p && U[v] > U[ctr]) {
 *              dfs(v, u, ctr, ...);
 *          }
 *      }
 * }
 */
template <typename EdgeType>
class CentroidDecomposition {
public:
        CentroidDecomposition(const vector<vector<EdgeType>> &E) : E(E) {}

        const vector<int>& findCentroids() {
                DFSOrder<EdgeType> DFS(E);
                auto EF = DFS.linearize();
                
                N = E.size();
                U.assign(N, -1);

                for (int j = 0; j < N; ) {
                        for (int i = N - 1; i >= 0; --i) {
                                if (U[i] >= 0) continue;

                                U[i] = -1;
                                bool root = true;
                                for (auto v : EF[i]) {
                                        if (U[t(v)] < 0) {
                                                if (t(v) > i) U[i] += U[t(v)];
                                                else root = false;
                                        }
                                }

                                if (root) {
                                        int n = -U[i], u = i, p = -1;
                                        while (true) {
                                                int s = n + U[u];
                                                for (auto v : EF[u]) if (t(v) != p && U[t(v)] < 0) s = max(s, -U[t(v)]);
                                                if (2 * s <= n) {
                                                        U[u] = j++;
                                                        break;
                                                } else {
                                                        for (auto v : EF[u]) if (t(v) != p && -U[t(v)] > n / 2) {
                                                                        p = u;
                                                                        u = t(v);
                                                                        break;
                                                                }
                                                }
                                        }
                                }
                        }
                }
                vector<int> Ans(N);
                for (int i = 0; i < N; ++i) Ans[i] = U[DFS.enter()[i]];
                swap(Ans, U);
                return U;
        }

        inline int t(const int&e) const {
                return e;
        }
        template <typename U> inline int t(const pair<int, U>&e) const {
                return e.x;
        }

        int N;
        const vector<vector<EdgeType>> &E;
        vector<int> U;
};

template<typename F>struct NoOp {
        void setup(ui, F) {} void op(F&p, F n, ui, ui) {
                p = n;
        } void down(F&, F&, F&, ui, ui) {}
};

template<typename F, typename SetOp, typename PowerOp>struct Lazy {
        void setup(ui s, F def) {
                this->def = def;
                this->s = s;
                L = new F[s]();
                fill(L, L + s, def);
        }
        void down(F&u, F&l, F&r, ui i, ui s) {
                op(l, L[i], i << 1, s>>1);
                op(r, L[i], i << 1 | 1, s >> 1);
                L[i] = def;
        }
        void op(F&p, F n, ui i, ui s) {
                p = sop(p, pop(n, s));
                if(i < this->s)this->L[i] = sop(this->L[i], n);
        }
        SetOp sop;
        PowerOp pop;
        F*L;
        ui s;
        F def;
};

template <typename F, typename CombineOp, typename ModifyOp = NoOp<F>> struct SegTree {
        void setup(ui s, F def) {
                n = 1 << logceil(s);
                T = vector<F>(2 * n, def);
                for (ui i = n - 1; i > 0; i--) T[i] = cop(T[i << 1], T[i << 1 | 1]);
                mop.setup(2 * n, def);
        }

        void setup(vector<F> & data, F def = F(), F def2 = F()) {
                n = 1 << logceil(data.size());
                T = vector<F>(2 * n, def);
                copy(data.begin(), data.end(), T.begin() + n);
                for (ui i = n - 1; i > 0; i--) T[i] = cop(T[i << 1], T[i << 1 | 1]);
                mop.setup(2 * n, def2);
        }

        inline void put(ui x, F n) {
                put(x, x, n);
        }
        inline void put(ui from, ui to, F v) {
                put2(from, to + 1, v, 1, n);
        }
        inline F get(ui x) {
                return get(x, x);
        }
        inline F get(ui from, ui to) {
                return get2(from, to + 1, 1, n);
        }

        void put2(ui from, ui to, F v, ui i, ui s) {
                if (from == 0 && to == s) {
                        mop.op(T[i], v, i, s);
                        return;
                }
                mop.down(T[i], T[i << 1], T[i << 1 | 1], i, s);
                s >>= 1;
                i <<= 1;
                if (to <= s) {
                        put2(from, to, v, i, s);
                } else if (from >= s) {
                        put2(from - s, to - s, v, i | 1, s);
                } else {
                        put2(from, s, v, i, s);
                        put2(0, to - s, v, i | 1, s);
                }
                T[i >> 1] = cop(T[i], T[i | 1]);
        }

        F get2(ui from, ui to, ui i, ui s) {
                while (true) {
                        if (from == 0 && to == s) return T[i];
                        mop.down(T[i], T[i << 1], T[i << 1 | 1], i, s);
                        s >>= 1;
                        i <<= 1;
                        if (to > s) {
                                to -= s;
                                if (from >= s) {
                                        from -= s;
                                        i |= 1;
                                } else return cop(get2(from, s, i, s), get2(0, to, i | 1, s));
                        }
                }
        }

        ui n;
        vector<F> T;
        CombineOp cop;
        ModifyOp mop;
};


template <typename F> struct AddOp {
        F operator()(F a, F b) {
                return a + b;
        }
};
template <typename F> struct MinOp {
        F operator()(F a, F b) {
                return std::min(a, b);
        }
};
template <typename F> struct MaxOp {
        F operator()(F a, F b) {
                return std::max(a, b);
        }
};
template <typename F> struct MultiplyOp {
        F operator()(F a, F b) {
                return a * b;
        }
};
template <typename F> struct MultOp {
        F operator()(F a, ui b) {
                return a * b;
        }
};
template <typename F> struct IdempOp {
        F operator()(F a, ui b) {
                return a;
        }
};
template <typename F> struct InverseOp {
        F operator()(F a, F b) {
                return b ? b - a : a;
        }
};

template<typename T> using AddSumTree = SegTree<T, AddOp<T>, Lazy<T, AddOp<T>, MultOp<T>>>;
template<typename T> using AddMaxTree = SegTree<T, MaxOp<T>, Lazy<T, AddOp<T>, IdempOp<T>>>;
template<typename T> using AddMinTree = SegTree<T, MinOp<T>, Lazy<T, AddOp<T>, IdempOp<T>>>;
template<typename T> using AssignMinTree = SegTree<T, MinOp<T>, Lazy<T, MinOp<T>, IdempOp<T>>>;
template<typename T> using AssignMaxTree = SegTree<T, MaxOp<T>, Lazy<T, MaxOp<T>, IdempOp<T>>>;
template<typename T> using XorTree = SegTree<T, AddOp<T>, Lazy<T, InverseOp<T>, MultOp<T>>>;

template<typename T> using SetMinTree = SegTree<T, MinOp<T>>;
template<typename T> using SetMaxTree = SegTree<T, MaxOp<T>>;
template<typename T> using SetMulTree = SegTree<T, MultiplyOp<T>>;


class Diameter {
public:
        // all edges (target, initial_cost)
        vector<vector<pair<int, ll>>> E;

        // level on which vertex is a centroid
        vector<int> Level;

        // (u,v) -> (centroid, root_edge_id),(left,right)
        // left-right is range of leaves (by dfs visit time) that hang below this edge
        // size of each vector is <= log N (by centroid decomposition)
        unordered_map<pii, vector<pair<pii, pii>>> EdgeToCtr;

        // for each centroid, the sum of root to leaf path, leaves ordered by dfs visit times
        // only used in the setup phase, then superseded by LeafDepths
        vector<vector<ll>> RootToLeafPath;

        // for each centroid the prefix sums of the subtrees hanging under edges adjacent to centroid
        vector<vector<int>> CentroidChildSubtreeSizes;

        // range add and range max; initialised by LeafDepths
        vector<AddMaxTree<ll>> LeafDepths;

        // per centroid, maximum root-to-leaf path for each edge adjacent to centroid
        vector<multiset<ll>> CtrMax;

        // per centroid, maximum cost path in that centroid
        multiset<ll> AllMax;

        void dfs(int u, int p, int ctr, int j, ll cost, int &T) {
                bool isLeaf = true;
                for (auto v : E[u]) {
                        if (v.x != p && Level[v.x] > Level[ctr]) {
                                isLeaf = false;
                                int begin = T;
                                dfs(v.x, u, ctr, j, cost + v.y, T);
                                int end = T;
                                EdgeToCtr[ {u, v.x}].push_back({{ctr, j}, {begin, end - 1}});
                                EdgeToCtr[ {v.x, u}].push_back({{ctr, j}, {begin, end - 1}});
                        }
                }

                if (isLeaf) {
                        RootToLeafPath[ctr].push_back(cost);
                        T++;
                }
        }

        void buildForCentroid(int u) {
                CentroidChildSubtreeSizes[u].push_back(0);
                int root_edges = 0, T = 0;
                for (auto v : E[u]) {
                        if (Level[v.x] > Level[u]) {
                                int begin = T;
                                dfs(v.x, u, u, ++root_edges, v.y, T);
                                int end = T;
                                EdgeToCtr[ {u, v.x}].push_back({{u, root_edges}, {begin, end - 1}});
                                EdgeToCtr[ {v.x, u}].push_back({{u, root_edges}, {begin, end - 1}});
                                CentroidChildSubtreeSizes[u].push_back(T);
                        }
                }

                if (root_edges > 0) {
                        LeafDepths[u].setup(RootToLeafPath[u], 0LL);
                        for (int i = 1; i <= root_edges; ++i) {
                                CtrMax[u].insert(maxForRootEdge(u, i));
                        }
                        AllMax.insert(maxForCentroid(u));
                }
        }

        ll maxForRootEdge(int u, int i) {
                return LeafDepths[u].get(CentroidChildSubtreeSizes[u][i - 1], CentroidChildSubtreeSizes[u][i] - 1);
        }

        ll maxForCentroid(int u) {
                if (CtrMax[u].empty()) {
                        return 0LL;
                } else if (CtrMax[u].size() == 1) {
                        return *CtrMax[u].rbegin();
                } else {
                        return *CtrMax[u].rbegin() + *next(CtrMax[u].rbegin());
                }
        }

        void remove(multiset<ll>&M, ll x) {
                M.erase(M.find(x));
        }

        void solve(istream& cin, ostream& cout) {
                int N, Q; ll W;
                cin >> N >> Q >> W;
                vector<pair<int, int> > _edges;
                vector<ll> _edge_w;

                E.resize(N);
                _edges.resize(N);
                _edge_w.resize(N);

                RootToLeafPath.resize(N);
                CentroidChildSubtreeSizes.resize(N);
                LeafDepths.resize(N);
                CtrMax.resize(N);
                for (int i = 0; i < N - 1; ++i) {
                        int a, b;
                        ll c;
                        
                        cin >> a >> b >> c;
                        --a;
                        --b;
                        _edges[i] = {a, b};
                        _edge_w[i] = c;
                        E[a].emplace_back(b, c);
                        E[b].emplace_back(a, c);
                }


                CentroidDecomposition<pair<int, ll>> C{E};
                Level = C.findCentroids();
                for (int i = 0; i < N; ++i) {
                        buildForCentroid(i);
                }

                ll last = 0; //*AllMax.rbegin();
                int cnt = 0;
                for (int q = 0; q < Q; ++q) {
                        int i;
                        ll c;
                        cin >> i >> c;
                        i = (i + last) % (N - 1);
                        c = (c + last) % W;
                        auto [a, b] = _edges[i];
                        ll rel_c = c - _edge_w[i];
                        _edge_w[i] = c;

                        // process (a,b) in all centroids in which this edge exists
                        for (auto e : EdgeToCtr[ {a, b}]) {
                                int ctr = e.x.x;
                                int i = e.x.y;
                                int l = e.y.x;
                                int r = e.y.y;

                                remove(AllMax, maxForCentroid(ctr));
                                remove(CtrMax[ctr], maxForRootEdge(ctr, i));

                                LeafDepths[ctr].put(l, r, rel_c);

                                CtrMax[ctr].insert(maxForRootEdge(ctr, i));
                                AllMax.insert(maxForCentroid(ctr));
                        }

                        ll cur = *AllMax.rbegin();
                        cout << cur << '\n';
                        //cnt += last != cur;
                        last = cur;
                }
                //cerr << cnt << '\n';
        }
};


int main() {
        ios_base::sync_with_stdio(false);
        cin.tie(nullptr);
        cout.tie(nullptr);
        Diameter solver;
        std::istream& in(std::cin);
        std::ostream& out(std::cout);
        solver.solve(in, out);
        return 0;
}

Compilation message (stderr)

diameter.cpp: In member function 'void Diameter::solve(std::istream&, std::ostream&)':
diameter.cpp:443:21: warning: unused variable 'cnt' [-Wunused-variable]
                 int cnt = 0;
                     ^~~
diameter.cpp: In instantiation of 'DFSOrder<EdgeType>::DFSOrder(const std::vector<std::vector<_Tp> >&) [with EdgeType = std::pair<int, long long int>]':
diameter.cpp:115:36:   required from 'const std::vector<int>& CentroidDecomposition<EdgeType>::findCentroids() [with EdgeType = std::pair<int, long long int>]'
diameter.cpp:437:41:   required from here
diameter.cpp:89:34: warning: 'DFSOrder<std::pair<int, long long int> >::RevEnter' will be initialized after [-Wreorder]
         vector<int> Enter, Exit, RevEnter;
                                  ^~~~~~~~
diameter.cpp:89:21: warning:   'std::vector<int> DFSOrder<std::pair<int, long long int> >::Enter' [-Wreorder]
         vector<int> Enter, Exit, RevEnter;
                     ^~~~~
diameter.cpp:42:9: warning:   when initialized here [-Wreorder]
         DFSOrder(const vector<vector<EdgeType>> &_E) : T(0), N(_E.size()), E(_E), RevEnter(N), Enter(N), Exit(N) {
         ^~~~~~~~
#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...