結果
| 問題 |
No.235 めぐるはめぐる (5)
|
| コンテスト | |
| ユーザー |
|
| 提出日時 | 2024-11-21 15:05:26 |
| 言語 | C++23 (gcc 13.3.0 + boost 1.87.0) |
| 結果 |
AC
|
| 実行時間 | 1,623 ms / 10,000 ms |
| コード長 | 13,795 bytes |
| コンパイル時間 | 4,928 ms |
| コンパイル使用メモリ | 287,020 KB |
| 実行使用メモリ | 33,764 KB |
| 最終ジャッジ日時 | 2024-11-21 15:05:40 |
| 合計ジャッジ時間 | 12,306 ms |
|
ジャッジサーバーID (参考情報) |
judge1 / judge5 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| other | AC * 3 |
ソースコード
#ifndef LOCAL
#include <bits/stdc++.h>
using ll = long long;
using uint = unsigned int;
using ull = unsigned long long;
using ld = long double;
using i128 = __int128_t;
using u128 = __uint128_t;
namespace fastio {
static constexpr int BUF_SIZE = 1 << 20;
struct Pre {
char num[10000][4];
constexpr Pre() : num() {
for (int i = 0; i < 10000; i++) {
int n = i;
for (int j = 3; j >= 0; j--) {
num[i][j] = n % 10 | '0';
n /= 10;
}
}
}
} constexpr pre;
static struct FastOutput {
private:
static constexpr int TMP_SIZE = 1 << 10;
char tmp[TMP_SIZE];
char buf[BUF_SIZE];
size_t buf_pos = 0;
template <class T>
inline char* wt_integer(T x) {
char* p = tmp + TMP_SIZE - 1;
if (x == 0) {
*--p = '0';
} else {
bool is_negative = false;
if (x < 0) {
is_negative = true;
x = -x;
}
while (x >= 10000) {
memcpy(p -= 4, pre.num[x % 10000], 4);
x /= 10000;
}
if (x >= 1000) {
memcpy(p -= 4, pre.num[x], 4);
} else if (x >= 100) {
memcpy(p -= 3, pre.num[x] + 1, 3);
} else if (x >= 10) {
memcpy(p -= 2, pre.num[x] + 2, 2);
} else {
*--p = pre.num[x][3];
}
if (is_negative) *--p = '-';
}
return p;
}
template <class T, size_t N = 0>
inline void wt_tuple(const T& t) {
if constexpr (N < std::tuple_size<T>::value) {
if constexpr (N > 0) wt(' ');
const auto x = std::get<N>(t);
wt(x);
wt_tuple<T, N + 1>(t);
}
}
public:
inline void wt(char c) {
buf[buf_pos++] = c;
if (buf_pos == BUF_SIZE) flush();
}
inline void wt(const char* s) {
for (; *s != '\0'; s++) {
wt(*s);
}
}
inline void wt(const std::string& s) {
for (char c : s) wt(c);
}
template <class Tp>
inline std::enable_if_t<std::is_floating_point_v<Tp>>
wt(const Tp& x) {
std::ostringstream oss;
oss << std::fixed << std::setprecision(16) << x;
wt(oss.str());
}
template <class Tp>
inline std::enable_if_t<std::is_integral_v<Tp>>
wt(const Tp& x) { wt(wt_integer(x)); }
inline void wt(const __int128_t& x) { wt(wt_integer(x)); }
inline void wt(const __uint128_t& x) { wt(wt_integer(x)); }
template <class T, class U>
inline void wt(const std::pair<T, U>& p) {
wt(p.first);
wt(' ');
wt(p.second);
}
template <class... Args>
inline void wt(const std::tuple<Args...>& t) {
wt_tuple(t);
}
template <class T, size_t N = 0>
inline void wt(const std::array<T, N>& a) {
for (size_t i = 0; i < N; i++) {
if (i) wt(' ');
wt(a[i]);
}
}
template <class T>
inline void wt(const std::vector<T>& x) {
for (size_t i = 0; i < x.size(); i++) {
if (i) wt(' ');
wt(x[i]);
}
}
inline void flush() {
fwrite(buf, 1, buf_pos, stdout);
buf_pos = 0;
}
~FastOutput() { flush(); }
} fastout;
static struct FastInput {
private:
char buf[BUF_SIZE];
size_t buf_pos = 0;
size_t size = 0;
char cur = 0;
inline char rd_char() {
if (buf_pos >= size) {
size = fread(buf, 1, BUF_SIZE, stdin);
buf_pos = 0;
buf[0] = (size == 0 ? -1 : buf[0]);
}
return cur = buf[buf_pos++];
}
template <class Tp>
inline void rd_integer(Tp& x) {
x = Tp{};
if (skip_blanks()) {
int sign = +1;
if (cur == '-') {
sign = -1;
rd_char();
}
do {
x += x + (x << 3) + (cur & 15);
} while (!is_blank(rd_char()));
x *= sign;
}
}
inline bool is_blank(char c) { return c <= ' '; }
inline bool skip_blanks() {
while (is_blank(cur) && cur != -1) {
rd_char();
}
return cur != -1;
}
template <class T, size_t N = 0>
void rd_tuple(T& t) {
if constexpr (N < std::tuple_size<T>::value) {
auto& x = std::get<N>(t);
rd(x);
rd_tuple<T, N + 1>(t);
}
}
public:
inline void rd(char& c) {
skip_blanks();
c = cur;
}
inline void rd(std::string& s) {
if (skip_blanks()) {
s.clear();
do {
s += cur;
} while (!is_blank(rd_char()));
}
}
template <class T>
inline auto rd(T& x) -> std::void_t<std::enable_if_t<std::is_integral<T>::value>> { rd_integer(x); }
inline auto rd(__int128_t& x) { rd_integer(x); }
inline auto rd(__uint128_t& x) { rd_integer(x); }
inline void rd(double& x) {
std::string s;
rd(s);
x = std::stod(s);
}
inline void rd(long double& x) {
std::string s;
rd(s);
x = std::stold(s);
}
template <class T, class U>
void rd(std::pair<T, U>& p) {
rd(p.first);
rd(p.second);
}
template <class... Args>
void rd(std::tuple<Args...>& t) {
rd_tuple(t);
}
template <class T, size_t N>
void rd(std::array<T, N>& x) {
for (auto& d : x) rd(d);
}
template <class T>
void rd(std::vector<T>& x) {
for (auto& d : x) rd(d);
}
} fastin;
inline void flush() { fastout.flush(); }
void IN() {}
template <class Head, class... Tails>
void IN(Head& head, Tails&... tails) {
fastin.rd(head);
IN(tails...);
}
template <class Last>
void print(const Last& last) { fastout.wt(last); }
template <class Head, class... Tails>
void print(const Head& head, const Tails&... tails) {
fastout.wt(head);
fastout.wt(' ');
print(tails...);
}
template <class... Args>
void println(const Args&... args) {
print(args...);
fastout.wt('\n');
}
} // namespace fastio
using fastio::flush;
using fastio::IN;
using fastio::print;
using fastio::println;
#define INT(...) \
int __VA_ARGS__; \
IN(__VA_ARGS__)
#define LL(...) \
long long __VA_ARGS__; \
IN(__VA_ARGS__)
#define STR(...) \
string __VA_ARGS__; \
IN(__VA_ARGS__)
#define CHAR(...) \
char __VA_ARGS__; \
IN(__VA_ARGS__)
#define DBL(...) \
double __VA_ARGS__; \
IN(__VA_ARGS__)
#define VEC(type, name, size) \
vector<type> name(size); \
IN(name)
#define VV(type, name, h, w) \
vector<vector<type>> name(h, vector<type>(w)); \
IN(name)
#define debug(...) (void(0))
#else
#include "algo/debug.h"
#endif
template <class T>
struct Edge {
int from;
int to;
T cost;
friend bool operator<(const Edge<T>& lhs, const Edge<T>& rhs) {
return lhs.cost < rhs.cost;
}
friend bool operator>(const Edge<T>& lhs, const Edge<T>& rhs) {
return lhs.cost > rhs.cost;
}
};
template <class T>
struct Graph : public Edge<T> {
int N, M;
std::vector<std::vector<int>> G;
std::vector<Edge<T>> edges;
Graph() : N(0), M(0) {}
explicit Graph(int n) : N(n), M(0), G(n) {}
int add(int from, int to, T cost = 1, bool is_dir = false) {
assert(0 <= from && from < N);
assert(0 <= to && to < N);
edges.push_back({from, to, cost});
G[from].push_back(M);
if (!is_dir) G[to].push_back(M);
return M++;
}
const std::vector<int>& operator[](int p) const { return G[p]; }
std::vector<int>& operator[](int p) { return G[p]; }
};
template <class T>
struct HeavyLightDecomposition {
std::vector<int> sz, head, in, out, par, dep, vid;
private:
int N, k;
const Graph<T>& G;
int dfs_sz(int v, int p = -1) {
sz[v] = 1;
for (int id : G[v]) {
const auto& e = G.edges[id];
int to = v ^ e.from ^ e.to;
if (to == p) continue;
dep[to] = dep[v] + 1;
sz[v] += dfs_sz(to, v);
}
return sz[v];
}
void dfs_hld(int v, int p = -1) {
in[v] = k++;
vid[in[v]] = v;
par[v] = p;
int best = -1, bnode = -1;
for (const int id : G[v]) {
const auto& e = G.edges[id];
int to = v ^ e.from ^ e.to;
if (to == p) continue;
if (sz[to] > best) {
best = sz[to];
bnode = to;
}
}
if (bnode != -1) {
head[bnode] = head[v];
dfs_hld(bnode, v);
}
for (const int id : G[v]) {
const auto& e = G.edges[id];
int to = v ^ e.from ^ e.to;
if (to == p || to == bnode) continue;
head[to] = to;
dfs_hld(to, v);
}
out[v] = k;
}
public:
HeavyLightDecomposition() = default;
HeavyLightDecomposition(const Graph<T>& g, int root = 0)
: HeavyLightDecomposition(g, std::vector<int>{root}) {}
HeavyLightDecomposition(const Graph<T>& g, const std::vector<int>& roots) : G(g) {
N = G.N;
sz.assign(N, -1);
dep.resize(N);
for (int r : roots) dfs_sz(r);
for (int i = 0; i < N; i++)
if (sz[i] == -1) dfs_sz(i);
k = 0;
head.assign(N, -1);
in.resize(N);
out.resize(N);
par.assign(N, -1);
vid.resize(N);
for (int r : roots) {
head[r] = r;
dfs_hld(r);
}
for (int i = 0; i < N; i++) {
if (head[i] == -1) {
head[i] = i;
dfs_hld(i);
}
}
}
int get(int p) const { return in[p]; }
int depth(int p) const { return dep[p]; }
int operator[](int p) const { return get(p); }
int size(int p) const { return sz[p]; }
int kth_anc(int v, int k) {
while (v >= 0) {
int u = head[v];
if (in[v] - k >= in[u]) return vid[in[v] - k];
k -= in[v] - in[u] + 1;
v = par[u];
}
return -1;
}
int jump(int u, int v, int d) {
int l = lca(u, v);
int d1 = dep[u] - dep[l];
if (d <= d1) return kth_anc(u, d);
int d2 = d1 + dep[v] - dep[l];
if (d <= d2) return kth_anc(v, d2 - d);
return -1;
}
std::pair<int, int> subtree(int p) const { return {in[p], out[p]}; }
int lca(int u, int v) const {
while (head[u] != head[v]) {
if (in[u] > in[v]) std::swap(u, v);
v = par[head[v]];
}
return in[u] > in[v] ? v : u;
}
std::vector<std::pair<int, int>> ascend(int u, int v) const {
std::vector<std::pair<int, int>> res;
while (head[u] != head[v]) {
res.emplace_back(in[u], in[head[u]]);
u = par[head[u]];
}
if (u != v) res.emplace_back(in[u], in[v] + 1);
return res;
}
std::vector<std::pair<int, int>> descend(int u, int v) const {
std::vector<std::pair<int, int>> res = ascend(v, u);
for (auto&& [a, b] : res) std::swap(a, b);
std::reverse(res.begin(), res.end());
return res;
}
template <class F>
void path_vertex(int u, int v, const F& f) const {
path_vertex(u, v, f, f);
}
template <class F, class G>
void path_vertex(int u, int v, const F& f, const G& g) const {
int l = lca(u, v);
const auto func = [&](int a, int b) -> void {
if (a <= b)
f(a, b + 1);
else
g(b, a + 1);
};
for (const auto& [a, b] : ascend(u, l)) func(a, b);
func(in[l], in[l]);
for (const auto& [a, b] : descend(l, v)) func(a, b);
}
template <class F>
void path_edge(int u, int v, const F& f) const {
return path_edge(u, v, f, f);
}
template <class F, class G>
void path_edge(int u, int v, const F& f, const G& g) const {
int l = lca(u, v);
const auto func = [&](int a, int b) -> void {
if (a <= b)
f(a, b + 1);
else
g(b, a + 1);
};
for (const auto& [a, b] : ascend(u, l)) func(a, b);
for (const auto& [a, b] : descend(l, v)) func(a, b);
}
};
#include <atcoder/lazysegtree>
#include <atcoder/modint>
using mint = atcoder::modint1000000007;
struct S {
mint val, coef;
};
S op(S a, S b) {
return S{a.val + b.val, a.coef + b.coef};
}
S e() { return S{0, 0}; }
ll id() { return 0; }
S mapp(ll f, S x) {
return S{x.val + x.coef * f, x.coef};
}
ll comp(ll f, ll g) { return f + g; }
void solve() {
using namespace std;
INT(N);
VEC(int, T, N);
VEC(ll, C, N);
Graph<int> G(N);
for (int i = 1; i < N; i++) {
INT(a, b);
G.add(a - 1, b - 1);
}
HeavyLightDecomposition hld(G);
atcoder::lazy_segtree<S, op, e, ll, mapp, comp, id> seg(N);
for (int i = 0; i < N; i++) seg.set(hld[i], S{T[i], C[i]});
INT(Q);
while (Q--) {
INT(o);
if (o == 0) {
INT(x, y, z);
hld.path_vertex(x - 1, y - 1, [&](int a, int b) -> void {
seg.apply(a, b, z);
});
} else {
INT(x, y);
mint ans = 0;
hld.path_vertex(x - 1, y - 1, [&](int a, int b) -> void {
ans += seg.prod(a, b).val;
});
cout << ans.val() << endl;
}
}
}
int main() {
int T = 1;
// std::cin >> T;
while (T--) {
solve();
}
}