結果

問題 No.650 行列木クエリ
ユーザー risujirohrisujiroh
提出日時 2020-03-06 09:31:44
言語 C++14
(gcc 12.3.0 + boost 1.83.0)
結果
AC  
実行時間 111 ms / 2,000 ms
コード長 5,813 bytes
コンパイル時間 2,008 ms
コンパイル使用メモリ 188,032 KB
実行使用メモリ 32,652 KB
最終ジャッジ日時 2024-10-14 02:40:29
合計ジャッジ時間 4,033 ms
ジャッジサーバーID
(参考情報)
judge4 / judge2
このコードへのチャレンジ
(要ログイン)

テストケース

テストケース表示
入力 結果 実行時間
実行使用メモリ
testcase_00 AC 2 ms
5,248 KB
testcase_01 AC 36 ms
6,656 KB
testcase_02 AC 102 ms
20,312 KB
testcase_03 AC 2 ms
5,248 KB
testcase_04 AC 37 ms
6,656 KB
testcase_05 AC 111 ms
20,304 KB
testcase_06 AC 2 ms
5,248 KB
testcase_07 AC 2 ms
5,248 KB
testcase_08 AC 39 ms
9,212 KB
testcase_09 AC 93 ms
32,652 KB
testcase_10 AC 2 ms
5,248 KB
権限があれば一括ダウンロードができます

ソースコード

diff #

#include <bits/stdc++.h>
using namespace std;

template <class T> struct tree {
  struct edge {
    int u, v;
    T w;
  };
  const int n;
  vector<edge> es;
  vector<vector<int>> g;
  vector<int> pv, pe, sz, dep, vs, in, out, head;
  vector<T> dist;
  tree(int _n = 0) : n(_n), g(n) {}
  void add_edge(int u, int v, T w = 1) {
    g[u].push_back(es.size()), g[v].push_back(es.size());
    es.push_back({u, v, w});
  }
  int other(int id, int v) { return es[id].u ^ es[id].v ^ v; }
  void dfs(int v) {
    sz[v] = 1;
    for (int& id : g[v]) {
      if (id == pe[v]) continue;
      int to = other(id, v);
      assert(pv[to] == -1);
      pv[to] = v, pe[to] = id;
      dep[to] = dep[v] + 1, dist[to] = dist[v] + es[id].w;
      dfs(to);
      sz[v] += sz[to];
      if (g[v][0] == pv[v] or sz[to] > sz[other(g[v][0], v)]) swap(g[v][0], id);
    }
  }
  void build(int r = 0) {
    assert((int)es.size() == n - 1);
    pv.assign(n, -1), pe.resize(n), sz.resize(n), dep.resize(n), dist.resize(n);
    pe[r] = -1, dep[r] = 0, dist[r] = 0;
    dfs(r);
  }
  void dfs_hld(int v) {
    in[v] = vs.size(), vs.push_back(v);
    for (int id : g[v]) {
      if (id == pe[v]) continue;
      int to = other(id, v);
      head[to] = to == other(g[v][0], v) ? head[v] : to;
      dfs_hld(to);
    }
    out[v] = vs.size();
  }
  void build_hld(int r = 0) {
    build(r);
    vs.clear(), in.resize(n), out.resize(n), head.resize(n);
    head[r] = r;
    dfs_hld(r);
  }
  bool anc(int u, int v) const { return in[u] <= in[v] and out[v] <= out[u]; }
  int lca(int u, int v) const {
    while (true) {
      if (in[u] > in[v]) swap(u, v);
      if (head[u] == head[v]) return u;
      v = pv[head[v]];
    }
  }
  int la(int v, int d) const {
    assert(0 <= d and d <= dep[v]);
    while (dep[head[v]] > d) v = pv[head[v]];
    return vs[in[head[v]] + (d - dep[head[v]])];
  }
  int next(int from, int to) const {
    assert(from != to);
    if (not anc(from, to)) return pv[from];
    return la(to, dep[from] + 1);
  }
  vector<pair<int, int>> ascend(int from, int to) const {
    assert(anc(to, from));
    vector<pair<int, int>> res;
    while (head[from] != head[to]) {
      res.emplace_back(in[from], in[head[from]]);
      from = pv[head[from]];
    }
    if (from != to) res.emplace_back(in[from], in[to] + 1);
    return res;
  }
  vector<pair<int, int>> descend(int from, int to) const {
    assert(anc(from, to));
    if (from == to) return {};
    if (head[from] == head[to]) return {{in[from] + 1, in[to]}};
    auto res = descend(from, pv[head[to]]);
    res.emplace_back(in[head[to]], in[to]);
    return res;
  }
  template <class F> void run(int from, int to, F f, bool vertex = true) const {
    int v = lca(from, to);
    for (auto e : ascend(from, v)) f(e.first + 1, e.second);
    if (vertex) f(in[v], in[v] + 1);
    for (auto e : descend(v, to)) f(e.first, e.second + 1);
  }
};

template <class T, class Op = function<T(T, T)>> struct segtree {
  const Op op;
  const T e = T();
  const int n = 0;
  vector<T> t;
  T& operator[](int i) { return t[n + i]; }
  void build() { for (int i = n; i--; ) t[i] = op(t[2 * i], t[2 * i + 1]); }
  T fold(int l, int r) const {
    T a = e, b = e;
    for (l += n, r += n; l < r; l >>= 1, r >>= 1) {
      if (l & 1) a = op(a, t[l++]);
      if (r & 1) b = op(t[--r], b);
    }
    return op(a, b);
  }
  void set(int i, T a) {
    t[i += n] = a;
    while (i >>= 1) t[i] = op(t[2 * i], t[2 * i + 1]);
  }
};
template <class T, class Op> auto make_segtree(int n, Op op, T e) {
  return segtree<T, Op>{op, e, n, vector<T>(2 * n, e)};
}

template <unsigned M> struct modular {
  using m = modular;
  unsigned v;
  modular(long long x = 0) : v((x %= M) < 0 ? x + M : x) {}
  m operator-() const { return m() -= *this; }
  m& operator+=(m b) { if ((v += b.v) >= M) v -= M; return *this; }
  m& operator-=(m b) { if (v < b.v) v += M; v -= b.v; return *this; }
  m& operator*=(m b) { v = (uint64_t)v * b.v % M; return *this; }
  friend m operator+(m a, m b) { return a += b; }
  friend m operator-(m a, m b) { return a -= b; }
  friend m operator*(m a, m b) { return a *= b; }
  friend bool operator==(m a, m b) { return a.v == b.v; }
  friend string to_string(m a) { return to_string(a.v); }
};

constexpr long long mod = 1e9 + 7;
using mint = modular<mod>;

using mat = array<array<mint, 2>, 2>;
mat operator*(const mat& a, const mat& b) {
  mat c;
  for (int i : {0, 1}) {
    for (int k : {0, 1}) {
      for (int j : {0, 1}) {
        c[i][j] += a[i][k] * b[k][j];
      }
    }
  }
  return c;
}

int main() {
  cin.tie(nullptr);
  ios::sync_with_stdio(false);
  int n;
  cin >> n;
  tree<int> g(n);
  for (int id = 0; id < n - 1; ++id) {
    int u, v;
    cin >> u >> v;
    g.add_edge(u, v);
  }
  g.build_hld();
  mat e{1, 0, 0, 1};
  auto st = make_segtree<pair<mat, mat>>(n, [](const auto& a, const auto& b) {
    return make_pair(a.first * b.first, b.second * a.second);
  }, {e, e});
  int q;
  cin >> q;
  while (q--) {
    char c;
    cin >> c;
    if (c == 'x') {
      int id;
      cin >> id;
      int v = g.es[id].u;
      if (g.dep[v] < g.dep[g.es[id].v]) {
        v = g.es[id].v;
      }
      mat a;
      cin >> a[0][0].v >> a[0][1].v >> a[1][0].v >> a[1][1].v;
      st.set(g.in[v], {a, a});
    } else {
      int u, v;
      cin >> u >> v;
      mat a = e;
      g.run(u, v, [&](int l, int r) {
        if (l < r) {
          a = a * st.fold(l, r).first;
        } else {
          a = a * st.fold(r, l).second;
        }
      }, false);
      cout << a[0][0].v << ' ' << a[0][1].v << ' ' << a[1][0].v << ' ' << a[1][1].v << '\n';
    }
  }
}
0