#line 2 "/home/shogo314/cpp_include/ou-library/rerooting-dp.hpp"
/**
* @file rerooting-dp.hpp
* @brief 全方位木DP
*/
#include <algorithm>
#include <cstddef>
#include <type_traits>
#line 2 "/home/shogo314/cpp_include/ou-library/tree.hpp"
/**
* @file tree.hpp
* @brief 木の汎用テンプレート
*/
#line 9 "/home/shogo314/cpp_include/ou-library/tree.hpp"
#include <stack>
#include <tuple>
#line 2 "/home/shogo314/cpp_include/ou-library/graph.hpp"
#include <iostream>
#include <limits>
#include <queue>
#include <vector>
/**
* @brief グラフの汎用クラス
*
* @tparam Cost 辺のコストの型
*/
template <typename Cost=int>
struct Graph {
/**
* @brief 有向辺の構造体
*
* operator int()を定義しているので、int型にキャストすると勝手にdstになる
* 例えば、
* for (auto& e : g[v]) をすると、vから出る辺が列挙されるが、
* for (int dst : g[v]) とすると、vから出る辺の行き先が列挙される
*/
struct Edge {
int src; //!< 始点
int dst; //!< 終点
Cost cost; //!< コスト
int id; //!< 辺の番号(追加された順、無向辺の場合はidが同じで方向が逆のものが2つ存在する)
Edge() = default;
Edge(int src, int dst, Cost cost=1, int id=-1) : src(src), dst(dst), cost(cost), id(id) {}
operator int() const { return dst; }
};
int n; //!< 頂点数
int m; //!< 辺数
std::vector<std::vector<Edge>> g; //!< グラフの隣接リスト表現
/**
* @brief デフォルトコンストラクタ
*/
Graph() : n(0), m(0), g(0) {}
/**
* @brief コンストラクタ
* @param n 頂点数
*/
explicit Graph(int n) : n(n), m(0), g(n) {}
/**
* @brief 無向辺を追加する
* @param u 始点
* @param v 終点
* @param w コスト 省略したら1
*/
void add_edge(int u, int v, Cost w=1) {
g[u].push_back({u, v, w, m});
g[v].push_back({v, u, w, m++});
}
/**
* @brief 有向辺を追加する
* @param u 始点
* @param v 終点
* @param w コスト 省略したら1
*/
void add_directed_edge(int u, int v, Cost w=1) {
g[u].push_back({u, v, w, m++});
}
/**
* @brief 辺の情報を標準入力から受け取って追加する
* @param m 辺の数
* @param padding 頂点番号を入力からいくつずらすか 省略したら-1
* @param weighted 辺の重みが入力されるか 省略したらfalseとなり、重み1で辺が追加される
* @param directed 有向グラフかどうか 省略したらfalse
*/
void read(int m, int padding=-1, bool weighted=false, bool directed=false) {
for(int i = 0; i < m; i++) {
int u, v; std::cin >> u >> v; u += padding, v += padding;
Cost c(1);
if(weighted) std::cin >> c;
if(directed) add_directed_edge(u, v, c);
else add_edge(u, v, c);
}
}
/**
* @brief ある頂点から出る辺を列挙する
* @param v 頂点番号
* @return std::vector<Edge>& vから出る辺のリスト
*/
std::vector<Edge>& operator[](int v) {
return g[v];
}
/**
* @brief ある頂点から出る辺を列挙する
* @param v 頂点番号
* @return const std::vector<Edge>& vから出る辺のリスト
*/
const std::vector<Edge>& operator[](int v) const {
return g[v];
}
/**
* @brief 辺のリスト
* @return std::vector<Edge> 辺のリスト(idの昇順)
*
* 無向辺は代表して1つだけ格納される
*/
std::vector<Edge> edges() const {
std::vector<Edge> res(m);
for(int i = 0; i < n; i++) {
for(auto& e : g[i]) {
res[e.id] = e;
}
}
return res;
}
/**
* @brief ある頂点から各頂点への最短路
*
* @param s 始点
* @param weighted 1以外のコストの辺が存在するか 省略するとtrue
* @param inf コストのminの単位元 未到達の頂点への距離はinfになる 省略すると-1
* @return std::pair<std::vector<Cost>, std::vector<Edge>> first:各頂点への最短路長 second:各頂点への最短路上の直前の辺
*/
std::pair<std::vector<Cost>, std::vector<Edge>> shortest_path(int s, bool weignted = true, Cost inf = -1) const {
if(weignted) return shortest_path_dijkstra(s, inf);
return shortest_path_bfs(s, inf);
}
std::vector<int> topological_sort() {
std::vector<int> indeg(n), sorted;
std::queue<int> q;
for (int i = 0; i < n; i++) {
for (int dst : g[i]) indeg[dst]++;
}
for (int i = 0; i < n; i++) {
if (!indeg[i]) q.push(i);
}
while (!q.empty()) {
int cur = q.front(); q.pop();
for (int dst : g[cur]) {
if (!--indeg[dst]) q.push(dst);
}
sorted.push_back(cur);
}
return sorted;
}
private:
std::pair<std::vector<Cost>, std::vector<Edge>> shortest_path_bfs(int s, Cost inf) const {
std::vector<Cost> dist(n, inf);
std::vector<Edge> prev(n);
std::queue<int> que;
dist[s] = 0;
que.push(s);
while(!que.empty()) {
int u = que.front(); que.pop();
for(auto& e : g[u]) {
if(dist[e.dst] == inf) {
dist[e.dst] = dist[e.src] + 1;
prev[e.dst] = e;
que.push(e.dst);
}
}
}
return {dist, prev};
}
std::pair<std::vector<Cost>, std::vector<Edge>> shortest_path_dijkstra(int s, Cost inf) const {
std::vector<Cost> dist(n, inf);
std::vector<Edge> prev(n);
using Node = std::pair<Cost, int>;
std::priority_queue<Node, std::vector<Node>, std::greater<Node>> que;
dist[s] = 0;
que.push({0, s});
while(!que.empty()) {
auto [d, u] = que.top(); que.pop();
if(d > dist[u]) continue;
for(auto& e : g[u]) {
if(dist[e.dst] == inf || dist[e.dst] > dist[e.src] + e.cost) {
dist[e.dst] = dist[e.src] + e.cost;
prev[e.dst] = e;
que.push({dist[e.dst], e.dst});
}
}
}
return {dist, prev};
}
};
#line 13 "/home/shogo314/cpp_include/ou-library/tree.hpp"
template <typename>
struct RootedTree;
template <typename>
struct DoublingClimbTree;
/**
* @brief 根なし木
*
* @tparam Cost = int 辺の重み
*
* Graph<Cost>を継承し、すべて無向辺で表す
*/
template <typename Cost = int>
struct Tree : private Graph<Cost> {
// Graph<Cost>* g = new Tree<Cost>(); ができてしまうと、delete時にメモリリークが発生
// 回避するためprivate継承にして、メンバをすべてusing宣言
using Edge = typename Graph<Cost>::Edge;
using Graph<Cost>::n;
using Graph<Cost>::m;
using Graph<Cost>::g;
using Graph<Cost>::Graph;
using Graph<Cost>::add_edge;
using Graph<Cost>::add_directed_edge;
using Graph<Cost>::read;
using Graph<Cost>::operator[];
using Graph<Cost>::edges;
using Graph<Cost>::shortest_path;
/**
* @brief コンストラクタ
*
* @param n ノード数
*/
Tree(int n = 0) : Graph<Cost>(n) {}
/**
* @brief 辺の情報を標準入力から受け取って追加する
* @param padding = -1 頂点番号を入力からいくつずらすか
* @param weighted = false 辺の重みが入力されるか
*/
void read(int padding = -1, bool weighted = false) {
Graph<Cost>::read(this->n - 1, padding, weighted, false);
}
/**
* @brief 木の直径
*
* @param weighted = true 重み付きか
* @return std::vector<Edge> 直径を構成する辺のリスト
*/
std::vector<Edge> diameter(bool weighted = true) const {
std::vector<Cost> dist = shortest_path(0, weighted).first;
int u = std::max_element(dist.begin(), dist.end()) - dist.begin();
std::vector<Edge> prev;
std::tie(dist, prev) = shortest_path(u, weighted);
int v = std::max_element(dist.begin(), dist.end()) - dist.begin();
std::vector<Edge> path;
while(v != u) {
path.push_back(prev[v]);
v = prev[v].src;
}
reverse(path.begin(), path.end());
return path;
}
/**
* @brief 根付き木にする
*
* @param root 根
* @return RootedTree<Cost> 根付き木のオブジェクト
*/
[[nodiscard]]
RootedTree<Cost> set_root(int root) const& {
return RootedTree<Cost>(*this, root);
}
/**
* @brief 根付き木にして返す
*
* @param root 根
* @return RootedTree<Cost> 根付き木のオブジェクト
*/
[[nodiscard]]
RootedTree<Cost> set_root(int root) && {
return RootedTree<Cost>(std::move(*this), root);
}
/**
* @brief ダブリングLCAが使える根付き木を返す
*
* @param root 根
* @return DoublingClimbTree<Cost> ダブリング済み根付き木のオブジェクト
*/
[[nodiscard]]
DoublingClimbTree<Cost> build_lca(int root) const& {
RootedTree rooted_tree(*this, root);
return DoublingClimbTree<Cost>(std::move(rooted_tree));
}
/**
* @brief ダブリングLCAが使える根付き木を返す
*
* @param root 根
* @return DoublingClimbTree<Cost> ダブリング済み根付き木のオブジェクト
*/
[[nodiscard]]
DoublingClimbTree<Cost> build_lca(int root) && {
RootedTree rooted_tree(std::move(*this), root);
return DoublingClimbTree<Cost>(std::move(rooted_tree));
}
};
/**
* @brief 根付き木
*
* @tparam Cost = int 辺のコスト
*/
template <typename Cost = int>
struct RootedTree : private Tree<Cost> {
using Edge = typename Tree<Cost>::Edge;
using Tree<Cost>::n;
using Tree<Cost>::m;
using Tree<Cost>::g;
using Tree<Cost>::operator[];
using Tree<Cost>::edges;
using Tree<Cost>::shortest_path;
int root; //!< 根
std::vector<Edge> par; //!< 親へ向かう辺
std::vector<std::vector<Edge>> child; //!< 子へ向かう辺のリスト
std::vector<Cost> depth; //!< 深さのリスト
std::vector<Cost> height; //!< 部分木の高さのリスト
std::vector<int> unweighted_depth; //!< 重みなしの深さのリスト
std::vector<int> unweighted_height; //!< 重みなしの部分木の高さのリスト
std::vector<int> sz; //!< 部分期の頂点数のリスト
std::vector<int> preorder; //!< 先行順巡回
std::vector<int> postorder; //!< 後行順巡回
std::vector<std::pair<int, int>> euler_tour; //!< オイラーツアー DFS中にとおった頂点の(頂点番号,その頂点を通った回数)のリスト
RootedTree() = delete;
/**
* @brief 親の頂点のリストから根が0の根付き木を構築するコンストラクタ
*
* @param par_ 頂点0以外の親の頂点のリスト
* @param padding = -1 parの頂点番号をいくつずらすか
*/
RootedTree(const std::vector<int>& par_, int padding = -1) : Tree<Cost>(par_.size() + 1), root(0) {
for(int i = 0; i < (int)par_.size(); i++) {
this->add_edge(i + 1, par_[i] + padding);
}
build();
}
/**
* @brief Treeから根付き木を構築するコンストラクタ(コピー)
*
* @param tree Tree
* @param root 根
*/
RootedTree(const Tree<Cost>& tree, int root) : Tree<Cost>(tree), root(root) {
build();
}
/**
* @brief Treeから根付き木を構築するコンストラクタ(ムーブ)
*
* @param tree Tree
* @param root 根
*/
RootedTree(Tree<Cost>&& tree, int root) : Tree<Cost>(std::move(tree)), root(root) {
build();
}
/**
* @brief ダブリングLCAが使える根付き木を得る
*
* @return DoublingClimbTree<Cost> ダブリング済み根付き木のオブジェクト
*/
[[nodiscard]]
DoublingClimbTree<Cost> build_lca() const& {
return DoublingClimbTree<Cost>(*this);
}
/**
* @brief ダブリングLCAが使える根付き木を得る
*
* @return DoublingClimbTree<Cost> ダブリング済み根付き木のオブジェクト
*/
[[nodiscard]]
DoublingClimbTree<Cost> build_lca() && {
return DoublingClimbTree<Cost>(std::move(*this));
}
private:
void build() {
int n = this->n;
par.resize(n);
par[root] = {root, -1, 0, -1};
child.resize(n);
depth.resize(n);
unweighted_depth.resize(n);
height.resize(n);
unweighted_height.resize(n);
sz.resize(n);
std::vector<int> iter(n);
std::stack<std::pair<int, int>> stk;
stk.emplace(root, 0);
while(!stk.empty()) {
auto [u, cnt] = stk.top(); stk.pop();
euler_tour.emplace_back(u, cnt);
if(iter[u] == 0) preorder.push_back(u);
while(iter[u] < (int)this->g[u].size() && this->g[u][iter[u]].dst == par[u]) iter[u]++;
if(iter[u] == (int)this->g[u].size()) {
postorder.push_back(u);
sz[u] = 1;
height[u] = 0;
unweighted_height[u] = 0;
for(auto& e : child[u]) {
sz[u] += sz[e.dst];
if(height[u] < height[e.dst] + e.cost) {
height[u] = height[e.dst] + e.cost;
}
if(unweighted_height[u] < unweighted_height[e.dst] + 1) {
unweighted_height[u] = unweighted_height[e.dst] + 1;
}
}
} else {
auto& e = this->g[u][iter[u]++];
par[e.dst] = {e.dst, u, e.cost, e.id};
child[u].push_back(e);
depth[e.dst] = depth[u] + e.cost;
unweighted_depth[e.dst] = unweighted_depth[u] + 1;
stk.emplace(u, cnt + 1);
stk.emplace(e.dst, 0);
}
}
}
};
/**
* @brief 親頂点ダブリング済み根付き木
*
* @tparam Cost = int 辺の重み(注: climbでは根の重みは考えない)
*/
template <typename Cost = int>
struct DoublingClimbTree : private RootedTree<Cost> {
using Edge = typename RootedTree<Cost>::Edge;
using RootedTree<Cost>::n;
using RootedTree<Cost>::m;
using RootedTree<Cost>::g;
using RootedTree<Cost>::operator[];
using RootedTree<Cost>::edges;
using RootedTree<Cost>::shortest_path;
using RootedTree<Cost>::root;
using RootedTree<Cost>::par;
using RootedTree<Cost>::child;
using RootedTree<Cost>::depth;
using RootedTree<Cost>::height;
using RootedTree<Cost>::sz;
using RootedTree<Cost>::preorder;
using RootedTree<Cost>::postorder;
using RootedTree<Cost>::euler_tour;
int h; //!< ダブリングの回数
std::vector<std::vector<int>> doubling_par; //!< jから(1<<i)頂点登った頂点(存在しない場合は-1)
DoublingClimbTree() = delete;
/**
* @brief RootedTreeからダブリング済み根付き木を構築するコンストラクタ(コピー)
*
* @param tree RootedTree
*/
DoublingClimbTree(const RootedTree<Cost>& tree) : RootedTree<Cost>(tree) {
build();
}
/**
* @brief RootedTreeからダブリング済み根付き木を構築するコンストラクタ(ムーブ)
*
* @param tree RootedTree
*/
DoublingClimbTree(RootedTree<Cost>&& tree) : RootedTree<Cost>(std::move(tree)) {
build();
}
/**
* @brief 親の頂点のリストから根が0のダブリング済み根付き木を構築するコンストラクタ
*
* @param par_ 頂点0以外の親の頂点のリスト
* @param padding = -1 parの頂点番号をいくつずらすか
*/
DoublingClimbTree(const std::vector<int>& par_, int padding = -1) : RootedTree<Cost>(par_, padding) {
build();
}
/**
* @brief Treeからダブリング済み根付き木を構築するコンストラクタ(コピー)
*
* @param tree Tree
* @param root 根
*/
DoublingClimbTree(const Tree<Cost>& tree, int root) : RootedTree<Cost>(tree, root) {
build();
}
/**
* @brief Treeからダブリング済み根付き木を構築するコンストラクタ(ムーブ)
*
* @param tree Tree
* @param root 根
*/
DoublingClimbTree(Tree<Cost>&& tree, int root) : RootedTree<Cost>(std::move(tree), root) {
build();
}
/**
* @brief 頂点uからk回を根の方向に遡った頂点
*
* @param u 元の頂点
* @param k 登る段数
* @return int k回登った頂点
*/
int climb(int u, int k) const {
for(int i = 0; i < h; i++) {
if(k >> i & 1) u = doubling_par[i][u];
if(u == -1) return -1;
}
return u;
}
/**
* @brief 最小共通祖先
*
* @param u 頂点1
* @param v 頂点2
* @return int LCAの頂点番号
*/
int lca(int u, int v) const {
if(this->unweighted_depth[u] > this->unweighted_depth[v]) std::swap(u, v);
v = climb(v, this->unweighted_depth[v] - this->unweighted_depth[u]);
if(u == v) return u;
for(int i = h - 1; i >= 0; i--) {
int nu = doubling_par[i][u];
int nv = doubling_par[i][v];
if(nu == -1) continue;
if(nu != nv) {
u = nu;
v = nv;
}
}
return this->par[u];
}
/**
* @brief 頂点間距離(重みなし)
*
* @param u 頂点1
* @param v 頂点2
* @return int uとv間の最短経路の辺の本数
*/
Cost dist(int u, int v) const {
return this->depth[u] + this->depth[v] - this->depth[lca(u, v)] * 2;
}
private:
void build() {
int n = this->n;
h = 1;
while((1 << h) < n) h++;
doubling_par.assign(h, std::vector<int>(n, -1));
for(int i = 0; i < n; i++) doubling_par[0][i] = this->par[i];
for(int i = 0; i < h - 1; i++) {
for(int j = 0; j < n; j++) {
if(doubling_par[i][j] != -1) {
doubling_par[i+1][j] = doubling_par[i][doubling_par[i][j]];
}
}
}
}
};
#line 11 "/home/shogo314/cpp_include/ou-library/rerooting-dp.hpp"
/**
* @brief 全方位木DP
* dp[u] = addnode(merge(addedge(dp[v1], uv1.cost, uv1.id), merge(addedge(dp[v2], uv2.cost, uv2.id), ...)), u) v_iはuの子
*
* @tparam E 可換モノイド
* @tparam V DPの型
* @param tree
* @param e 可換モノイドの単位元
* @param merge (E,E)->E 可換
* @param addedge (V,Cost,int)->E
* @param addnode (E,int)->V
* @return std::vector<V>
*/
template <typename E, typename V = E, class Merge, class AddEdge, class AddNode, typename Cost>
std::vector<V> rerooting_dp(const Tree<Cost>& tree, E e, Merge merge, AddEdge addedge, AddNode addnode) {
static_assert(std::is_invocable_r_v<E, Merge, E, E>);
static_assert(std::is_invocable_r_v<E, AddEdge, V, Cost, int>);
static_assert(std::is_invocable_r_v<V, AddNode, E, int>);
RootedTree<Cost> rooted(tree, 0);
std::vector<V> subdp(rooted.n);
for (int u : rooted.postorder) {
E tmp = e;
for (auto edge : rooted.child[u]) {
tmp = merge(tmp, addedge(subdp[edge.dst], edge.cost, edge.id));
}
subdp[u] = addnode(tmp, u);
}
std::vector<V> dp(rooted.n);
std::vector<E> pe(rooted.n, e);
for (int u : rooted.preorder) {
const auto& ch = rooted.child[u];
std::vector<E> ri(ch.size() + 1, e);
for (std::size_t i = ch.size(); i > 0; i--) {
ri[i - 1] = merge(ri[i], addedge(subdp[ch[i - 1].dst], ch[i - 1].cost, ch[i - 1].id));
}
dp[u] = addnode(merge(pe[u], ri[0]), u);
E le = pe[u];
for (std::size_t i = 0; i < ch.size(); i++) {
pe[ch[i].dst] = addedge(addnode(merge(le, ri[i + 1]), u), ch[i].cost, ch[i].id);
le = merge(le, addedge(subdp[ch[i].dst], ch[i].cost, ch[i].id));
}
}
return dp;
}
/**
* @brief 最も遠い頂点までの距離
*/
template <typename Cost>
inline std::vector<Cost> farthest_node_dist(const Tree<Cost>& tree) {
return rerooting_dp(
tree,
Cost{},
[](Cost a, Cost b) { return std::max<Cost>(a, b); },
[](Cost a, Cost c, int) { return a + c; },
[](Cost a, int) { return a; });
}
/**
* @brief 他の全ての頂点との距離の合計
*/
template <typename Cost>
inline std::vector<Cost> distance_sums(const Tree<Cost>& tree) {
using P = typename std::pair<Cost, int>;
auto tmp = rerooting_dp(
tree,
P{{}, 0},
[](P a, P b) { return P{a.first + b.first, a.second + b.second}; },
[](P a, Cost c, int) { return P{a.first + a.second * c, a.second}; },
[](P a, int) { return P{a.first, a.second + 1}; });
std::vector<Cost> res;
res.reserve(tree.n);
for (const P& s : tmp) res.push_back(s.first);
return res;
}
/**
* @brief その頂点を含む連結な部分グラフの個数
*/
template <typename V, typename Cost>
inline std::vector<V> connected_subgraph_count(const Tree<Cost>& tree) {
return rerooting_dp(
tree,
V(1),
[](V a, V b) { return a * b; },
[](V a, Cost c, int) { return a + 1; },
[](V a, int) { return a; });
}
#line 2 "/home/shogo314/cpp_include/sh-library/base/all"
#include <bits/stdc++.h>
#line 5 "/home/shogo314/cpp_include/sh-library/base/container_func.hpp"
#include <initializer_list>
#line 5 "/home/shogo314/cpp_include/sh-library/base/traits.hpp"
#define HAS_METHOD(func_name) \
namespace detail { \
template <class T, class = void> \
struct has_##func_name##_impl : std::false_type {}; \
template <class T> \
struct has_##func_name##_impl<T, std::void_t<decltype(std::declval<T>().func_name())>> \
: std::true_type {}; \
} \
template <class T> \
struct has_##func_name : detail::has_##func_name##_impl<T>::type {}; \
template <class T> \
inline constexpr bool has_##func_name##_v = has_##func_name<T>::value;
#define HAS_METHOD_ARG(func_name) \
namespace detail { \
template <class T, typename U, class = void> \
struct has_##func_name##_impl : std::false_type {}; \
template <class T, typename U> \
struct has_##func_name##_impl<T, U, std::void_t<decltype(std::declval<T>().func_name(std::declval<U>()))>> \
: std::true_type {}; \
} \
template <class T, typename U> \
struct has_##func_name : detail::has_##func_name##_impl<T, U>::type {}; \
template <class T, typename U> \
inline constexpr bool has_##func_name##_v = has_##func_name<T, U>::value;
HAS_METHOD(repr)
HAS_METHOD(type_str)
HAS_METHOD(initializer_str)
HAS_METHOD(max)
HAS_METHOD(min)
HAS_METHOD(reversed)
HAS_METHOD(sorted)
HAS_METHOD(sum)
HAS_METHOD(product)
HAS_METHOD(product_xor)
HAS_METHOD_ARG(count)
HAS_METHOD_ARG(find)
HAS_METHOD_ARG(lower_bound)
HAS_METHOD_ARG(upper_bound)
#define ENABLE_IF_T_IMPL(expr) std::enable_if_t<expr, std::nullptr_t> = nullptr
#define ENABLE_IF_T(...) ENABLE_IF_T_IMPL((__VA_ARGS__))
template <class C>
using mem_value_type = typename C::value_type;
template <class C>
using mem_difference_type = typename C::difference_type;
namespace detail {
template <class T, class = void>
struct is_sorted_container_impl : std::false_type {};
template <class T>
struct is_sorted_container_impl<std::set<T>> : std::true_type {};
template <class T>
struct is_sorted_container_impl<std::multiset<T>> : std::true_type {};
} // namespace detail
template <class T>
struct is_sorted_container : detail::is_sorted_container_impl<T>::type {};
template <class T>
inline constexpr bool is_sorted_container_v = is_sorted_container<T>::value;
#line 9 "/home/shogo314/cpp_include/sh-library/base/container_func.hpp"
#define METHOD_EXPAND(func) \
template <typename T, ENABLE_IF_T(has_##func##_v<T>)> \
inline constexpr auto func(const T &t) -> decltype(t.func()) { \
return t.func(); \
}
#define METHOD_AND_FUNC_ARG_EXPAND(func) \
template <typename T, typename U, ENABLE_IF_T(has_##func##_v<T, U>)> \
inline constexpr auto func(const T &t, const U &u) \
-> decltype(t.func(u)) { \
return t.func(u); \
} \
template <typename T, typename U, ENABLE_IF_T(not has_##func##_v<T, U>)> \
inline constexpr auto func(const T &t, const U &u) \
-> decltype(std::func(t.begin(), t.end(), u)) { \
return std::func(t.begin(), t.end(), u); \
}
METHOD_EXPAND(reversed)
template <class C, ENABLE_IF_T(not has_reversed_v<C>)>
inline constexpr C reversed(C t) {
std::reverse(t.begin(), t.end());
return t;
}
METHOD_EXPAND(sorted)
template <class C, ENABLE_IF_T(not has_sorted_v<C>)>
inline constexpr C sorted(C t, bool reverse = false) {
std::sort(t.begin(), t.end());
if (reverse) std::reverse(t.begin(), t.end());
return t;
}
template <class C, class F, ENABLE_IF_T(not has_sorted_v<C> and std::is_invocable_r_v<bool, F, mem_value_type<C>, mem_value_type<C>>)>
inline constexpr C sorted(C t, F f) {
std::sort(t.begin(), t.end(), f);
return t;
}
template <class C>
inline constexpr void sort(C &t, bool reverse = false) {
std::sort(t.begin(), t.end());
if (reverse) std::reverse(t.begin(), t.end());
}
template <class C, class F, ENABLE_IF_T(std::is_invocable_r_v<bool, F, mem_value_type<C>, mem_value_type<C>>)>
inline constexpr void sort(C &t, F f) {
std::sort(t.begin(), t.end(), f);
}
template <class C, class F, ENABLE_IF_T(std::is_invocable_v<F, mem_value_type<C>>)>
inline constexpr void sort_by_key(C &t, F f) {
std::sort(t.begin(), t.end(), [&](const mem_value_type<C> &left, const mem_value_type<C> &right) {
return f(left) < f(right);
});
}
template <class C>
inline constexpr void reverse(C &t) {
std::reverse(t.begin(), t.end());
}
METHOD_EXPAND(max)
template <class C, ENABLE_IF_T(not has_max_v<C> and is_sorted_container_v<C>)>
inline constexpr mem_value_type<C> max(const C &v) {
assert(v.begin() != v.end());
return *v.rbegin();
}
template <class C, ENABLE_IF_T(not has_max_v<C> and not is_sorted_container_v<C>)>
inline constexpr mem_value_type<C> max(const C &v) {
assert(v.begin() != v.end());
return *std::max_element(v.begin(), v.end());
}
template <typename T>
inline constexpr T max(const std::initializer_list<T> &v) {
return std::max(v);
}
METHOD_EXPAND(min)
template <class C, ENABLE_IF_T(not has_max_v<C> and is_sorted_container_v<C>)>
inline constexpr mem_value_type<C> min(const C &v) {
assert(v.begin() != v.end());
return *v.begin();
}
template <class C, ENABLE_IF_T(not has_max_v<C> and not is_sorted_container_v<C>)>
inline constexpr mem_value_type<C> min(const C &v) {
assert(v.begin() != v.end());
return *std::min_element(v.begin(), v.end());
}
template <typename T>
inline constexpr T min(const std::initializer_list<T> &v) {
return std::min(v);
}
METHOD_EXPAND(sum)
template <class C, ENABLE_IF_T(not has_sum_v<C>)>
inline constexpr mem_value_type<C> sum(const C &v) {
return std::accumulate(v.begin(), v.end(), mem_value_type<C>{});
}
template <typename T>
inline constexpr T sum(const std::initializer_list<T> &v) {
return std::accumulate(v.begin(), v.end(), T{});
}
METHOD_EXPAND(product)
template <class C, ENABLE_IF_T(not has_product_v<C>)>
inline constexpr mem_value_type<C> product(const C &v) {
return std::accumulate(v.begin(), v.end(), mem_value_type<C>{1}, std::multiplies<mem_value_type<C>>());
}
template <typename T>
inline constexpr T product(const std::initializer_list<T> &v) {
return std::accumulate(v.begin(), v.end(), T{1}, std::multiplies<T>());
}
METHOD_EXPAND(product_xor)
template <class C, ENABLE_IF_T(not has_product_xor_v<C>)>
inline constexpr mem_value_type<C> product_xor(const C &v) {
return std::accumulate(v.begin(), v.end(), mem_value_type<C>{0}, std::bit_xor<mem_value_type<C>>());
}
template <typename T>
inline constexpr T product_xor(const std::initializer_list<T> &v) {
return std::accumulate(v.begin(), v.end(), T{0}, std::bit_xor<T>());
}
template <class C>
inline constexpr mem_value_type<C> maximum_subarray(const C &v) {
assert(not v.empty());
auto itr = v.begin();
mem_value_type<C> tmp = *itr++;
mem_value_type<C> res = tmp;
while (itr != v.end()) {
tmp += *itr;
if (tmp < *itr) tmp = *itr;
if (res < tmp) res = tmp;
++itr;
}
return res;
}
template <class C>
inline constexpr mem_value_type<C> maximum_subarray(const C &v, mem_value_type<C> init) {
mem_value_type<C> res = init, tmp = init;
for (const auto &a : v) {
tmp += a;
if (tmp < init) tmp = init;
if (res < tmp) res = tmp;
}
return res;
}
METHOD_AND_FUNC_ARG_EXPAND(count)
METHOD_AND_FUNC_ARG_EXPAND(find)
METHOD_AND_FUNC_ARG_EXPAND(lower_bound)
METHOD_AND_FUNC_ARG_EXPAND(upper_bound)
template <class C, typename T>
inline constexpr bool contains(const C &c, const T &t) {
return find(c, t) != c.end();
}
template <class C>
inline constexpr mem_value_type<C> gcd(const C &v) {
mem_value_type<C> init(0);
for (const auto &e : v) init = std::gcd(init, e);
return init;
}
template <class C>
inline constexpr mem_value_type<C> average(const C &v) {
assert(v.size());
return sum(v) / v.size();
}
template <class C>
inline constexpr mem_value_type<C> median(const C &v) {
assert(not v.empty());
std::vector<size_t> u(v.size());
std::iota(u.begin(), u.end(), 0);
std::sort(u.begin(), u.end(), [&](size_t a, size_t b) {
return v[a] < v[b];
});
if (v.size() & 1) {
return v[u[v.size() / 2]];
}
// C++20
// return std::midpoint(v[u[v.size() / 2]], v[u[v.size() / 2 - 1]]);
return (v[u[v.size() / 2]] + v[u[v.size() / 2 - 1]]) / 2;
}
template <class C, typename U>
inline constexpr std::ptrdiff_t index(const C &v, const U &x) {
return std::distance(v.begin(), find(v, x));
}
template <class C, ENABLE_IF_T(std::is_integral_v<mem_value_type<C>>)>
inline constexpr mem_value_type<C> mex(const C &v) {
std::vector<bool> b(v.size() + 1);
for (const auto &a : v) {
if (0 <= a and a < b.size()) {
b[a] = true;
}
}
mem_value_type<C> ret;
for (size_t i = 0; i < b.size(); i++) {
if (not b[i]) {
ret = i;
break;
}
}
return ret;
}
template <class C>
inline constexpr mem_difference_type<C> bisect_left(const C &v, const mem_value_type<C> &x) {
return std::distance(v.begin(), lower_bound(v, x));
}
template <class C>
inline constexpr mem_difference_type<C> bisect_right(const C &v, const mem_value_type<C> &x) {
return std::distance(v.begin(), upper_bound(v, x));
}
#line 6 "/home/shogo314/cpp_include/sh-library/base/functions.hpp"
template <typename T1, typename T2>
inline constexpr bool chmin(T1 &a, T2 b) {
if (a > b) {
a = b;
return true;
}
return false;
}
template <typename T1, typename T2>
inline constexpr bool chmax(T1 &a, T2 b) {
if (a < b) {
a = b;
return true;
}
return false;
}
inline constexpr long long max(const long long &t1, const long long &t2) {
return std::max<long long>(t1, t2);
}
inline constexpr long long min(const long long &t1, const long long &t2) {
return std::min<long long>(t1, t2);
}
using std::abs;
using std::gcd;
using std::lcm;
using std::size;
template <typename T>
constexpr T extgcd(const T &a, const T &b, T &x, T &y) {
T d = a;
if (b != 0) {
d = extgcd(b, a % b, y, x);
y -= (a / b) * x;
} else {
x = 1;
y = 0;
}
return d;
}
template <typename M, typename N, class F, ENABLE_IF_T(std::is_integral_v<std::common_type_t<M, N>> and std::is_invocable_r_v<bool, F, std::common_type_t<M, N>>)>
inline constexpr std::common_type_t<M, N> binary_search(const M &ok, const N &ng, F f) {
std::common_type_t<M, N> _ok = ok, _ng = ng;
while (std::abs(_ok - _ng) > 1) {
std::common_type_t<M, N> mid = (_ok + _ng) / 2;
if (f(mid)) {
_ok = mid;
} else {
_ng = mid;
}
}
return _ok;
}
template <typename M, typename N, class F, ENABLE_IF_T(not std::is_integral_v<std::common_type_t<M, N>> and std::is_invocable_r_v<bool, F, std::common_type_t<M, N>>)>
inline constexpr std::common_type_t<M, N> binary_search(const M &ok, const N &ng, F f) {
std::common_type_t<M, N> _ok = ok, _ng = ng;
for (int i = 0; i < 100; i++) {
std::common_type_t<M, N> mid = (_ok + _ng) / 2;
if (f(mid)) {
_ok = mid;
} else {
_ng = mid;
}
}
return _ok;
}
/**
* 0 <= x < a
*/
inline constexpr bool inrange(long long x, long long a) {
return 0 <= x and x < a;
}
/**
* a <= x < b
*/
inline constexpr bool inrange(long long x, long long a, long long b) {
return a <= x and x < b;
}
/**
* 0 <= x < a and 0 <= y < b
*/
inline constexpr bool inrect(long long x, long long y, long long a, long long b) {
return 0 <= x and x < a and 0 <= y and y < b;
}
#line 8 "/home/shogo314/cpp_include/sh-library/base/io.hpp"
namespace tuple_io {
template <typename Tuple, size_t I, typename CharT, typename Traits>
std::basic_istream<CharT, Traits>& read_tuple(std::basic_istream<CharT, Traits>& is, Tuple& t) {
is >> std::get<I>(t);
if constexpr (I + 1 < std::tuple_size_v<Tuple>) {
return read_tuple<Tuple, I + 1>(is, t);
}
return is;
}
template <typename Tuple, size_t I, typename CharT, typename Traits>
std::basic_ostream<CharT, Traits>& write_tuple(std::basic_ostream<CharT, Traits>& os, const Tuple& t) {
os << std::get<I>(t);
if constexpr (I + 1 < std::tuple_size_v<Tuple>) {
os << CharT(' ');
return write_tuple<Tuple, I + 1>(os, t);
}
return os;
}
}; // namespace tuple_io
template <typename T1, typename T2, typename CharT, typename Traits>
std::basic_istream<CharT, Traits>& operator>>(std::basic_istream<CharT, Traits>& is, std::pair<T1, T2>& p) {
is >> p.first >> p.second;
return is;
}
template <typename... Types, typename CharT, typename Traits>
std::basic_istream<CharT, Traits>& operator>>(std::basic_istream<CharT, Traits>& is, std::tuple<Types...>& p) {
return tuple_io::read_tuple<std::tuple<Types...>, 0>(is, p);
}
template <typename T, size_t N, typename CharT, typename Traits>
std::basic_istream<CharT, Traits>& operator>>(std::basic_istream<CharT, Traits>& is, std::array<T, N>& a) {
for (auto& e : a) is >> e;
return is;
}
template <typename T, typename CharT, typename Traits>
std::basic_istream<CharT, Traits>& operator>>(std::basic_istream<CharT, Traits>& is, std::vector<T>& v) {
for (auto& e : v) is >> e;
return is;
}
template <typename T1, typename T2, typename CharT, typename Traits>
std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& os, const std::pair<T1, T2>& p) {
os << p.first << CharT(' ') << p.second;
return os;
}
template <typename... Types, typename CharT, typename Traits>
std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& os, const std::tuple<Types...>& p) {
return tuple_io::write_tuple<std::tuple<Types...>, 0>(os, p);
}
template <typename T, size_t N, typename CharT, typename Traits>
std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& os, const std::array<T, N>& a) {
for (size_t i = 0; i < N; ++i) {
if (i) os << CharT(' ');
os << a[i];
}
return os;
}
template <typename T, typename CharT, typename Traits>
std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& os, const std::vector<T>& v) {
for (size_t i = 0; i < v.size(); ++i) {
if (i) os << CharT(' ');
os << v[i];
}
return os;
}
template <typename T, typename CharT, typename Traits>
std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& os, const std::set<T>& s) {
for (auto itr = s.begin(); itr != s.end(); ++itr) {
if (itr != s.begin()) os << CharT(' ');
os << *itr;
}
return os;
}
/**
* @brief 空行出力
*/
void print() { std::cout << '\n'; }
/**
* @brief 出力して改行
*
* @tparam T 型
* @param x 出力する値
*/
template <typename T>
void print(const T& x) { std::cout << x << '\n'; }
/**
* @brief 空白区切りで出力して改行
*
* @tparam T 1つ目の要素の型
* @tparam Tail 2つ目以降の要素の型
* @param x 1つ目の要素
* @param tail 2つ目以降の要素
*/
template <typename T, typename... Tail>
void print(const T& x, const Tail&... tail) {
std::cout << x << ' ';
print(tail...);
}
/**
* @brief 空行出力
*/
void err() { std::cerr << std::endl; }
/**
* @brief 出力して改行
*
* @tparam T 型
* @param x 出力する値
*/
template <typename T>
void err(const T& x) { std::cerr << x << std::endl; }
/**
* @brief 空白区切りで出力して改行
*
* @tparam T 1つ目の要素の型
* @tparam Tail 2つ目以降の要素の型
* @param x 1つ目の要素
* @param tail 2つ目以降の要素
*/
template <typename T, typename... Tail>
void err(const T& x, const Tail&... tail) {
std::cerr << x << ' ';
err(tail...);
}
#line 3 "/home/shogo314/cpp_include/sh-library/base/type_alias.hpp"
using ll = long long;
using ull = unsigned long long;
using ld = long double;
template <typename T>
using vec = std::vector<T>;
template <typename T, int N>
using ary = std::array<T, N>;
using str = std::string;
using std::deque;
using std::list;
using std::map;
using std::multimap;
using std::multiset;
using std::pair;
using std::set;
using pl = pair<ll, ll>;
using pd = pair<ld, ld>;
template <typename T>
using vv = vec<vec<T>>;
template <typename T>
using vvv = vec<vec<vec<T>>>;
using vl = vec<ll>;
using vvl = vv<ll>;
using vvvl = vvv<ll>;
using vs = vec<str>;
using vc = vec<char>;
using vi = vec<int>;
using vb = vec<bool>;
template <typename T1, typename T2>
using vp = vec<pair<T1, T2>>;
using vpl = vec<pl>;
using vvpl = vv<pl>;
using vd = vec<ld>;
using vpd = vec<pd>;
template <int N>
using al = ary<ll, N>;
template <int N1, int N2>
using aal = ary<ary<ll, N2>, N1>;
template <int N>
using val = vec<al<N>>;
template <int N>
using avl = ary<vl,N>;
template <typename T>
using ml = std::map<ll, T>;
using mll = std::map<ll, ll>;
using sl = std::set<ll>;
using spl = set<pl>;
template <int N>
using sal = set<al<N>>;
template <int N>
using asl = ary<sl,N>;
template <typename T>
using heap_max = std::priority_queue<T, std::vector<T>, std::less<T>>;
template <typename T>
using heap_min = std::priority_queue<T, std::vector<T>, std::greater<T>>;
#line 3 "/home/shogo314/cpp_include/sh-library/base/macro.hpp"
#pragma GCC target("avx2")
#pragma GCC optimize("O3")
#pragma GCC optimize("unroll-loops")
#define all(obj) (obj).begin(), (obj).end()
#define CONCAT_IMPL(x, y) __CONCAT(x, y)
#define UNIQUE_ID(base) CONCAT_IMPL(base, __COUNTER__)
#define GET_MACRO(_1, _2, _3, _4, NAME, ...) NAME
#define rep4(i, a, n, t) for (long long i = static_cast<long long>(a), i##_loop_end = static_cast<long long>(n), i##_loop_step = static_cast<long long>(t); i < i##_loop_end; i += i##_loop_step)
#define rep3(i, a, n) for (long long i = static_cast<long long>(a), i##_loop_end = static_cast<long long>(n); i < i##_loop_end; ++i)
#define rep2(i, n) rep3(i, 0, n)
#define rep1(n) rep2(UNIQUE_ID(loop_counter_), n)
#define rep(...) GET_MACRO(__VA_ARGS__, rep4, rep3, rep2, rep1)(__VA_ARGS__)
#define repd4(i, a, n, t) for (long long i = static_cast<long long>(n) - 1, i##_loop_end = static_cast<long long>(a), i##_loop_step = static_cast<long long>(t); i >= i##_loop_end; i -= i##_loop_step)
#define repd3(i, a, n) for (long long i = static_cast<long long>(n) - 1, i##_loop_end = static_cast<long long>(a); i >= i##_loop_end; --i)
#define repd2(i, n) repd3(i, 0, n)
#define repd(...) GET_MACRO(__VA_ARGS__, repd4, repd3, repd2)(__VA_ARGS__)
#define rrep(i, n) rep(i, 1, (n) + 1)
#define rrepd(i, n) repd(i, 1, (n) + 1)
inline void scan(){}
template<class Head,class... Tail>
inline void scan(Head&head,Tail&... tail){std::cin>>head;scan(tail...);}
#define LL(...) ll __VA_ARGS__;scan(__VA_ARGS__)
#define STR(...) str __VA_ARGS__;scan(__VA_ARGS__)
#define IN(a, x) a x; std::cin >> x;
#define CHAR(x) char x; std::cin >> x;
#define VL(a,n) vl a(n); std::cin >> a;
#define AL(a,k) al<k> a; std::cin >> a;
#define AAL(a,n,m) aal<n,m> a; std::cin >> a;
#define VC(a,n) vc a(n); std::cin >> a;
#define VS(a,n) vs a(n); std::cin >> a;
#define VPL(a,n) vpl a(n); std::cin >> a;
#define VAL(a,n,k) val<k> a(n); std::cin >> a;
#define VVL(a,n,m) vvl a(n,vl(m)); std::cin >> a;
#define SL(a,n) sl a;{VL(b,n);a=sl(all(b));}
#define NO std::cout << "NO" << std::endl; return;
#define YES std::cout << "YES" << std::endl; return;
#define No std::cout << "No" << std::endl; return;
#define Yes std::cout << "Yes" << std::endl; return;
#define Takahashi std::cout << "Takahashi" << std::endl; return;
#define Aoki std::cout << "Aoki" << std::endl; return;
#line 7 "/home/shogo314/cpp_include/sh-library/base/vector_func.hpp"
#line 9 "/home/shogo314/cpp_include/sh-library/base/vector_func.hpp"
template <typename T>
std::vector<std::ptrdiff_t> sorted_idx(const std::vector<T> &v, bool reverse = false) {
std::vector<std::ptrdiff_t> ret(v.size());
std::iota(ret.begin(), ret.end(), 0);
std::sort(ret.begin(), ret.end(), [&](std::ptrdiff_t i, std::ptrdiff_t j) {
return v[i] < v[j];
});
if (reverse) std::reverse(ret.begin(), ret.end());
return ret;
}
template <typename T>
inline std::vector<T> &operator++(std::vector<T> &v) {
for (auto &e : v) e++;
return v;
}
template <typename T>
inline std::vector<T> operator++(std::vector<T> &v, int) {
auto res = v;
for (auto &e : v) e++;
return res;
}
template <typename T>
inline std::vector<T> &operator--(std::vector<T> &v) {
for (auto &e : v) e--;
return v;
}
template <typename T>
inline std::vector<T> operator--(std::vector<T> &v, int) {
auto res = v;
for (auto &e : v) e--;
return res;
}
template <typename T, typename U, ENABLE_IF_T(std::is_convertible_v<U, T>)>
inline std::vector<T> &operator+=(std::vector<T> &v1, const std::vector<U> &v2) {
if (v2.size() > v1.size()) {
v1.resize(v2.size());
}
for (size_t i = 0; i < v2.size(); i++) {
v1[i] += v2[i];
}
return v1;
}
template <typename T, typename U, ENABLE_IF_T(std::is_convertible_v<U, T>)>
inline std::vector<T> operator+(const std::vector<T> &v1, const std::vector<U> &v2) {
std::vector<T> res(v1);
return res += v2;
}
template <typename T, typename U, ENABLE_IF_T(std::is_convertible_v<U, T>)>
inline std::vector<T> &operator+=(std::vector<T> &v, const U &u) {
for (T &e : v) {
e += u;
}
return v;
}
template <typename T, typename U, ENABLE_IF_T(std::is_convertible_v<U, T>)>
inline std::vector<T> operator+(const std::vector<T> &v, const U &u) {
std::vector<T> res(v);
return res += u;
}
template <typename T, typename U, ENABLE_IF_T(std::is_convertible_v<U, T>)>
inline std::vector<T> operator+(const U &u, const std::vector<T> &v) {
std::vector<T> res(v);
return res += u;
}
template <typename T, typename U, ENABLE_IF_T(std::is_convertible_v<U, T>)>
inline std::vector<T> &operator*=(std::vector<T> &v1, const std::vector<U> &v2) {
if (v2.size() > v1.size()) {
v1.resize(v2.size());
}
for (size_t i = 0; i < v2.size(); i++) {
v1[i] *= v2[i];
}
for (size_t i = v2.size(); i < v1.size(); i++) {
v1[i] *= U(0);
}
return v1;
}
template <typename T, typename U, ENABLE_IF_T(std::is_convertible_v<U, T>)>
inline std::vector<T> operator*(const std::vector<T> &v1, const std::vector<U> &v2) {
std::vector<T> res(v1);
return res *= v2;
}
template <typename T, typename U, ENABLE_IF_T(std::is_convertible_v<U, T>)>
inline std::vector<T> &operator*=(std::vector<T> &v, const U &u) {
for (T &e : v) {
e *= u;
}
return v;
}
template <typename T, typename U, ENABLE_IF_T(std::is_convertible_v<U, T>)>
inline std::vector<T> operator*(const std::vector<T> &v, const U &u) {
std::vector<T> res(v);
return res *= u;
}
template <typename T, typename U, ENABLE_IF_T(std::is_convertible_v<U, T>)>
inline std::vector<T> operator*(const U &u, const std::vector<T> &v) {
std::vector<T> res(v);
return res *= u;
}
template <typename T, typename U>
inline std::vector<T> &assign(std::vector<T> &v1, const std::vector<U> &v2) {
v1.assign(v2.begin(), v2.end());
return v1;
}
template <typename T, typename U>
inline std::vector<T> &extend(std::vector<T> &v1, const std::vector<U> &v2) {
v1.insert(v1.end(), v2.begin(), v2.end());
return v1;
}
template <typename T, typename U, ENABLE_IF_T(std::is_convertible_v<U, T>)>
inline std::vector<T> &operator|=(std::vector<T> &v1, const std::vector<U> &v2) {
return extend(v1, v2);
}
template <typename T, typename U, ENABLE_IF_T(std::is_integral_v<U>)>
inline std::vector<T> &operator|=(std::vector<T> &v, const U &u) {
std::vector<T> w(v);
v.clear();
for (int i = 0; i < u; i++) {
extend(v, w);
}
return v;
}
template <typename T, typename U, ENABLE_IF_T(std::is_integral_v<U>)>
inline std::vector<T> operator|(const std::vector<T> &v, const U &u) {
std::vector<T> res(v);
return res |= u;
}
template <typename T, typename U, ENABLE_IF_T(std::is_integral_v<U>)>
inline std::vector<T> operator|(const U &u, const std::vector<T> &v) {
std::vector<T> res(v);
return res |= u;
}
template <typename T>
inline std::vector<T> abs(const std::vector<T> &v) {
std::vector<T> ret;
ret.reserve(v.size());
for (const T &e : v) ret.push_back(std::abs(e));
return ret;
}
template <typename T>
std::vector<T> cumulative_sum(std::vector<T> v) {
v.insert(v.begin(), T{});
std::vector<T> ret(v.size());
std::partial_sum(v.begin(), v.end(), ret.begin());
return ret;
}
template <typename T, ENABLE_IF_T(std::is_integral_v<T>)>
std::vector<T> iota(T n) {
assert(n >= 0);
std::vector<T> ret(n);
std::iota(ret.begin(), ret.end(), 0);
return ret;
}
template <typename T>
std::vector<T> unique(const std::vector<T> &v) {
std::vector<T> res(v);
std::sort(res.begin(), res.end());
res.erase(std::unique(res.begin(), res.end()), res.end());
return res;
}
long long radix_convert(const std::vector<long long> &v, int base = 10) {
long long res = 0;
for (int i = v.size() - 1; i >= 0; i--) {
res <<= base;
res += v[i];
}
return res;
}
std::vector<long long> radix_convert(long long v, int base = 10) {
std::vector<long long> res;
while (v > 0) {
res.push_back(v % base);
v /= base;
}
std::reverse(res.begin(), res.end());
return res;
}
#line 5 "/home/shogo314/cpp_include/sh-library/base/bit.hpp"
/**
* @brief 2進数の文字列をlong longにする
*/
long long btoll(std::string s, char one = '1') {
long long res = 0;
for (char c : s) {
res <<= 1;
if (c == one) ++res;
}
return res;
}
#if __cplusplus < 202000L
/**
* @brief 立っているビットを数える
* __builtin_popcountll
*/
int popcount(long long a) {
assert(a >= 0);
return __builtin_popcountll((unsigned long long)a);
}
/**
* @brief 左から連続した0のビットを数える
* __builtin_clzll
*/
int countl_zero(long long a) {
assert(a >= 0);
return __builtin_clzll((unsigned long long)a);
}
/**
* @brief 右から連続した0のビットを数える
* __builtin_ctzll
*/
int countr_zero(long long a) {
assert(a >= 0);
return __builtin_ctzll((unsigned long long)a);
}
#else
#include <bit>
#define BIT_FUNC_EXPAND(func) \
inline constexpr long long func(long long a) { \
assert(a >= 0); \
return std::func((unsigned long long)a); \
}
/**
* @brief 立っているビットを数える
*/
BIT_FUNC_EXPAND(popcount)
/**
* @brief 左から連続した0のビットを数える
*/
BIT_FUNC_EXPAND(countl_zero)
/**
* @brief 左から連続した1のビットを数える
*/
BIT_FUNC_EXPAND(countl_one)
/**
* @brief 右から連続した0のビットを数える
*/
BIT_FUNC_EXPAND(countr_zero)
/**
* @brief 右から連続した1のビットを数える
*/
BIT_FUNC_EXPAND(countr_one)
/**
* @brief 整数値を2の累乗値に切り上げる
*/
BIT_FUNC_EXPAND(bit_ceil)
/**
* @brief 整数値を2の累乗値に切り下げる
*/
BIT_FUNC_EXPAND(bit_floor)
/**
* @brief 値を表現するために必要なビット幅を求める
*/
BIT_FUNC_EXPAND(bit_width)
#endif
#line 4 "main.cpp"
void solve() {
constexpr ll INF = 1e18;
LL(N);
VL(W, N);
Tree<ll> tree(N);
tree.read(-1, true);
val<3> tmp = rerooting_dp(
tree,
al<3>{-INF, -INF, -INF},
[](al<3> a, al<3> b) { return al<3>{max(a[0], b[0]), max(a[1], b[1]), max(a[2], b[2])}; },
[](al<3> a, ll c, int) { return al<3>{a[0] - 2 * c, a[1] - 2 * c, a[2] - 2 * c}; },
[&](al<3> a, int i) { return al<3>{W[i], a[0]+W[i], max(a[1], a[2])+W[i]}; });
ll ans = -INF;
rep(i, N) {
chmax(ans, tmp[i][2]);
}
print(ans);
}
int main() {
std::cin.tie(nullptr);
std::ios_base::sync_with_stdio(false);
LL(T);
rep(T)
solve();
}