제출 #1349650

#제출 시각아이디문제언어결과실행 시간메모리
1349650edoHarmonija (COCI25_harmonija)C++20
87 / 110
2557 ms183248 KiB
#include <bits/stdc++.h>

using namespace std;
using ll = long long;
const ll inf = (1ll << 60);

struct Mat {
  ll a[5][5];
  Mat() {
    for (int i = 0; i < 5; ++i) {
      for (int j = 0; j < 5; ++j) {
        a[i][j] = -inf;
      }
    }
  }
};

Mat id() {
  Mat m;
  for (int i = 0; i < 5; ++i)
    m.a[i][i] = 0;
  return m;
}

Mat operator*(const Mat &x, const Mat &y) {
  Mat res;
  for (int i = 0; i < 5; ++i) {
    for (int j = 0; j < 5; ++j) {
      for (int k = 0; k < 5; ++k) {
        res.a[i][j] = max(res.a[i][j], x.a[i][k] + y.a[k][j]);
      }
    }
  }
  return res;
}
vector<int> c, p;

Mat single(int u) {
  Mat m;
  for (int b = 0; b < 5; ++b) {
    if (b + 1 < 5)
      m.a[b][b + 1] = c[u];
    if (b - 1 >= 0)
      m.a[b][b - 1] = p[u];
  }
  return m;
}

struct Node {
  Mat fw, bw;
};

Node merge(const Node &L, const Node &R) { return {L.fw * R.fw, R.bw * L.bw}; }

struct Seg {
  int n;
  vector<Node> st;
  vector<int> *rev;
  Seg(int n, vector<int> &rev) : n(n), st(4 * n), rev(&rev) {}

  Node neutral() {
    Mat I = id();
    return {I, I};
  }

  void build(int p, int l, int r) {
    if (l == r) {
      int u = (*rev)[l];
      Mat m = single(u);
      st[p] = {m, m};
      return;
    }
    int m = (l + r) >> 1;
    build(p << 1, l, m);
    build(p << 1 | 1, m + 1, r);
    st[p] = merge(st[p << 1], st[p << 1 | 1]);
  }

  Node qry(int p, int l, int r, int ql, int qr) {
    if (ql > r || qr < l)
      return neutral();
    if (ql <= l && qr >= r)
      return st[p];
    int m = (l + r) >> 1;
    Node L = qry(p << 1, l, m, ql, qr);
    Node R = qry(p << 1 | 1, m + 1, r, ql, qr);
    return merge(L, R);
  }
};

int main() {
  ios::sync_with_stdio(false);
  cin.tie(nullptr);

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

  c.resize(n);
  p.resize(n);
  for (int &i : c)
    cin >> i;
  for (int &i : p)
    cin >> i;

  vector<vector<int>> g(n);
  for (int i = 1, u, v; i < n; ++i) {
    cin >> u >> v, --u, --v;
    g[u].push_back(v);
    g[v].push_back(u);
  }

  vector<int> par(n, -1), depth(n), sz(n), heavy(n, -1), head(n), pos(n),
      rev(n);

  auto dfs1 = [&](auto &&self, int u, int p) -> void {
    par[u] = p;
    sz[u] = 1;
    int best = 0;
    for (int v : g[u]) {
      if (v ^ p) {
        depth[v] = depth[u] + 1;
        self(self, v, u);
        sz[u] += sz[v];
        if (sz[v] > best) {
          best = sz[v];
          heavy[u] = v;
        }
      }
    }
  };

  int timer = 0;
  auto dfs2 = [&](auto &&self, int u, int h) -> void {
    head[u] = h;
    pos[u] = timer;
    rev[timer] = u;
    timer++;
    if (~heavy[u]) {
      self(self, heavy[u], h);
    }
    for (int v : g[u]) {
      if (v == par[u] || v == heavy[u])
        continue;
      self(self, v, v);
    }
  };

  dfs1(dfs1, 0, -1);
  dfs2(dfs2, 0, 0);

  Seg seg(n, rev);
  seg.build(1, 0, n - 1);

  auto qry_path = [&](int u, int v) -> Mat {
    Mat left = id(), right = id();
    while (head[u] != head[v]) {
      if (depth[head[u]] > depth[head[v]]) {
        Mat cur = seg.qry(1, 0, n - 1, pos[head[u]], pos[u]).bw;
        left = left * cur;
        u = par[head[u]];
      } else {
        Mat cur = seg.qry(1, 0, n - 1, pos[head[v]], pos[v]).fw;
        right = cur * right;
        v = par[head[v]];
      }
    }
    if (depth[u] > depth[v]) {
      Mat cur = seg.qry(1, 0, n - 1, pos[v], pos[u]).bw;
      left = left * cur;
    } else {
      Mat cur = seg.qry(1, 0, n - 1, pos[u], pos[v]).fw;
      right = cur * right;
    }
    return left * right;
  };

  while (q--) {
    int u, v;
    cin >> u >> v, --u, --v;

    Mat tot = qry_path(u, v);
    ll ans = -inf;
    for (int j = 0; j < 5; ++j)
      ans = max(ans, tot.a[2][j]);
    cout << ans << "\n";

    // vector<int> par(n, -1);
    // queue<int> qu;
    // qu.push(u);
    // par[u] = u;
    // while (qu.size()) {
    //   int x = qu.front();
    //   qu.pop();
    //   if (x == v)
    //     break;
    //   for (int to : g[x]) {
    //     if (!~par[to]) {
    //       par[to] = x;
    //       qu.push(to);
    //     }
    //   }
    // }
    //
    // vector<int> path;
    // int cur = v;
    // for (; cur != u; cur = par[cur])
    //   path.push_back(cur);
    // path.push_back(u);
    // reverse(path.begin(), path.end());
    // vector<ll> dp(5, -inf), ndp(5, -inf);
    // dp[2] = 0;
    // for (int x : path) {
    //   fill(ndp.begin(), ndp.end(), -inf);
    //   for (int b = 0; b < 5; ++b) {
    //     if (dp[b] == -inf)
    //       continue;
    //     if (b + 1 < 5) {
    //       ndp[b + 1] = max(ndp[b + 1], dp[b] + c[x]);
    //     }
    //     if (b - 1 >= 0) {
    //       ndp[b - 1] = max(ndp[b - 1], dp[b] + p[x]);
    //     }
    //   }
    //   dp.swap(ndp);
    // }
    // cout << ranges::max(dp) << "\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...