NOI2023 D2T1
树上没有横叉边,因此任意一条
前半部分只能是
为什么这是一种简化?因为整个图是满二叉树,所以层数
下面设
因此,计算
为了能够精确扫描到需要的边和节点,计算
现在理论上所有的
#include <bits/stdc++.h>
#define int long long
inline int read() {
int x = 0; bool f = true; char ch = getchar();
for (; !isdigit(ch); ch = getchar()) if (ch == '-') f = false;
for (; isdigit(ch); ch = getchar()) x = (x << 1) + (x << 3) + ch - '0';
return f ? x : (~(x - 1));
}
typedef std :: pair <int, int> pii;
const int N = 1 << 20;
const int mod = 998244353;
int a[N], f[N], dis[N], n, m;
std :: vector <pii> G[N], R[N];
std :: vector <int> T[N];
int solve(int s, int o) {
std :: priority_queue <pii> q;
for (int u = (s << 1 | o); u; u >>= 1) {
dis[u] = (int)1e17;
G[u].emplace_back(u >> 1, a[u]);
}
for (int u : T[s << 1 | o]) {
dis[u] = (int)1e17;
for (pii e : R[u]) G[e.first].emplace_back(u, e.second);
}
dis[s] = 0; q.emplace(0, s);
while (!q.empty()) {
int d = q.top().first, u = q.top().second;
q.pop();
if (d + dis[u]) continue;
for (pii e: G[u]) {
int v = e.first, w = e.second;
if (dis[v] > dis[u] + w) {
dis[v] = dis[u] + w;
q.emplace(-dis[v], v);
}
}
}
int ans = 0;
for (int u : T[s << 1 | o]) if (dis[u] < (int)1e17)
(ans += (dis[u] + a[s << 1 | (o ^ 1)]) * (int)T[s << 1].size() % mod + f[s << 1 | (o ^ 1)] + dis[u]) %= mod;
for (int u : T[s << 1 | o]) std :: vector <pii> ().swap(G[u]);
for (int u = s; u; u >>= 1) std :: vector <pii> ().swap(G[u]);
return ans;
}
signed main() {
n = (1 << read()) - 1; m = read();
for (int u = 2; u <= n; ++u)
R[u >> 1].emplace_back(u, a[u] = read());
for (int i = 1; i <= m; ++i) {
int u = read(), v = read(), w = read();
R[v].emplace_back(u, w);
}
for (int u = 1; u <= n; ++u)
for (int v = u; v; v >>= 1)
T[v].push_back(u);
for (int u = n >> 1; u; --u)
f[u] = (f[u << 1] + f[u << 1 | 1] + (a[u << 1] + a[u << 1 | 1]) * (int)T[u << 1].size()) % mod;
int ans = 0;
for (int u = 1; u <= (n >> 1); ++u)
(ans += solve(u, 0) + solve(u, 1) + f[u]) %= mod;
printf("%lld\n", ans);
return 0;
}