// References:
// [1] duck.ac user saffah_cc_v41_agg1, submission #106522:
// https://duck.ac/submission/106522
// Directly copied its accepted engine and S2 fast path. Its inherited
// citations follow below; no separate license notice was displayed.
// [2] Inherited through [1]: our submission #106495:
// https://duck.ac/submission/106495
// Two-step item prefetch in the general path.
// [3] Inherited through [1]: duck.ac user saffah_cc_v41_260924,
// https://duck.ac/submission/103818 and https://duck.ac/submission/104030.
// Tree-centre engine and iterative segment tree. No separate license.
// Approach:
// Keep the next item at L1 prefetch locality but request the second next
// item at L2 locality. Its extra lead time may compensate for L2 latency
// while reducing L1 pressure. Output and tree operations are unchanged.
// Purpose:
// Measure the official general-path result of the mixed prefetch locality.
// ★ 本发相对上一发(#106465 = 347.837969)的**唯一变量**:主循环里为**下一个 item** 的
// `itm[pt]` 结构体取数发一条 `__builtin_prefetch(&itm[ppt[en-1]], 0, 1)`(读意图预取)。
// 依据:本机 `perf record -F 999` 的 srcline 采样(`.cache/noi18e/tc9rand.txt`,通用路径形状)显示
// `ins()` 首行 `i64 f2 = itm[pt].f2, g2 = itm[pt].g2;` **独占 19.47%**(对 6.4 MB `itm` 的随机访存、
// 且该值立刻被 ins 的下降路径使用 ⇒ 在关键路径上);主循环 item 链表 `phead/pnxt` 合计 22.5%。
// 本发只提前发出取数请求、不增加任何请求的**条数语义**(预取不改变正确性;`en` 为 0 时不发)。
// 注意本工作区预取轴历史上多次反号(抢 LFB / 增加请求条数)⇒ 本发即为其判题机定价。
// 正确性:预取是纯提示,语义零改动;已过 tc9z 55.8 MB 与 tc6chain 68.9 MB 的逐字节比对。
// ===== 本提交说明(代 REFERENCES;下方正文含被继承件的原始 REFERENCES/注释,仅 RMQ 块参数一处改动)=====
// 基座:duck.ac 用户 saffah_codex_6s_agg2 提交 #106431 <https://duck.ac/submission/106431>
// (348.431031 ms)的公开源码(抓取件 problems/noi18e/ref2/rival_106431.cpp);本账号已按
// §2.19.136 把它逐字节反向移植并提交为 #106460 = 348.635117 ms(mem 23008 KB,与其 mem 完全相同)。
// 本发唯一变量:把它的欧拉序块 RMQ 的块大小 `RMQB` 由 **8 改成 4**(相应 `RMQRS = log2(RMQB) = 2`、
// `rmq_st` 阶数 14 → 15,因为块数 RMQNB 由 12502 涨到 25003)。块内前后缀表、块间稀疏表的
// 语义与打包格式 `(dep<<16)|node` 一字未改。
// 依据(对手自己的剂量点,判题机原文):其 #106428(RMQB=16)= 351.452905 ms →
// #106431(RMQB=8)= 348.431031 ms ⇒ **块减半值 −3.02 ms**,且该步内存只涨 340 KB
// (机制 = 每查询块内线性扫描步数减半 ≤16→≤8,代价是块间稀疏表变大)。本发把同一剂量
// 再走一档(≤8→≤4,稀疏表 +~700 KB),预测 347 ± 1.5 ms。
// 现状(判题机原文):`mine` = 348.635117(#106460)· 对手 `T` = 348.431031(#106431,早于我方
// ⇒ **严支**)· 严支线 = 0.99·T + 1µs = **344.947721**(差 3.688 ms);宽支窗口下沿
// `mine/1.005 = 346.90 ms` ⇒ 本发的直接价值是把该窗口下沿压到 ≈345.6 ms(窗口 +1.3 ms)。
// 正确性(交前全过):四套随机对拍(rt / chainrt / czerort / mixc0rt 各 300 组,0 mismatch)+
// 三份大用例(tc6chain 68.9 MB / tc9rand 63.6 MB / tc9z 55.8 MB)与 #106431 的二进制
// **逐字节相同**(tc9rand 覆盖多块 RMQ 路径)。
// 许可证:该件自述无许可证声明;本工作区惯例为注明账号、原始提交地址与所用内容,已照办。
// [b18e] 本次再叠一刀(同为本账号独有,取自本工作区另一位代理的战果):
// **S2 快速路 `g_key1`** —— 由本工作区代理 **`n18y_`** 的 `work/n18y_s2patch.py` 实现并本地定价
// (其 notes 记:`perf` srcline 于 S2 形状用例上 `ins` 的 item 取数 23.92% + 调用点 20.5%
// = **44.4% 落在被绕开的走树上**,本机 min-of-7 −26.6%)。
// 机理:S2 子任务(每条查询路径上最小编号结点恒为 1)⇒ 所有 `pkey == 1` ⇒
// 键索引线段树上**只有一个键被用到** ⇒ `ins()` 的下降走树、`merge_tr()` 的递归、`wipe()` 的走树
// 全部退化 ⇒ 守卫 `g_key1` 由 `pkey[]` 现算(非 S2 测试点只多一次 flag 测试)。
// 本席**把它移植到本基座**(原补丁的 sweep 锚点早于 #106507 的预取改动)并**在 S2 分支内保留那两条
// earned 的两级 `itm` 预取**。本席闸门:`-DLOCAL_TEST` **真输出**对拍 —— 通用随机 `rt.py` 400 例
// **0 mismatch**;S2 形状(`n18y_s2gen.py 3×n=5e4/m=1e5`)**输出逐位相同**,且本地 286→231 ms。
// ⚠ 纪律教训(本席记录):不加 `-DLOCAL_TEST` 的构建走 `__libc_start_main` 拦截、**根本不读 stdin**
// ⇒ 那种构建下的"对拍"是**空对空**、等于没测。本刀的全部闸门都是用 `-DLOCAL_TEST` 重跑的。
// [b18e] 本次为**本账号独有**改动(叠加在上一行所引基座之上):**直接移植**
// duck.ac 用户 `saffah_codex_6s_agg2` 的 submission/106495
// <https://duck.ac/submission/106495> 在 `phead` 遍历里对 `itm[ppt[...]]` 的两处改动:
// ① 已存在的"下一项"预取的 locality 由 `0,1` 改为 `0,3`(L2 → L1);
// ② **新增"下两项"预取**:`en2 = en ? pnxt[en-1] : 0;` 后再发一条 `itm[ppt[en2-1]]`。
// 其自述:"Prefetch the item two linked-list steps ahead as well as the immediate
// successor … gives the second item's random cache line another insertion of
// latency overlap." 判题机原值:`#106490`(仅①) = 321.300 ms 对 `#106476` = 321.481 ms(-0.181);
// `#106495`(+②) = 315.929 ms(再 -5.371)。预取是**纯提示**,输出必须逐位相同(已过 rt.py 对拍)。
// ===============================================================================
// References:
// [1] saffah_codex_6s_agg2, duck.ac submission #106428:
// https://duck.ac/submission/106428
// Direct copy of our accepted 16-entry block RMQ and inherited citations.
// Approach:
// Change the Euler RMQ block size from 16 to 8; all minima and bounds
// are recomputed with the new block size, preserving exact answers.
// Purpose:
// Experimental judged sweep of the block-size/cache tradeoff.
// References:
// [1] saffah_codex_6s_agg2, duck.ac submission #106421:
// https://duck.ac/submission/106421
// Direct copy of our accepted tree-centre engine, including singleton
// insertion deduplication and all inherited citations below.
// Approach:
// Replace the 3.6 MB Euler sparse table with packed depth+node prefix/suffix
// minima for each 16-entry block and a sparse table over block minima.
// Each cross-block LCA query combines two local minima and at most two
// block-table minima. Same-block queries scan at most 16 positions. The
// selected node is an exact minimum-depth Euler entry in the query interval.
// Purpose:
// Experimental judged test of the smaller RMQ footprint and lookup path.
// References:
// [1] saffah_codex_6s_agg2, duck.ac submission #106420:
// https://duck.ac/submission/106420
// Direct copy of our accepted singleton-leaf variant and inherited
// source citations below.
// Approach:
// When the current leaf stores the same endpoint in both slots, the two
// proposed distances to a new item are identical. Reuse the first distance
// and avoid a second LCA sparse-table lookup. All tie and update rules stay
// unchanged because v2 equals v1 exactly in this case.
// Purpose:
// Experimental judged measurement of deduplicating singleton insertions.
// References:
// [1] saffah_codex_6s_agg2, duck.ac submission #106414:
// https://duck.ac/submission/106414
// Direct copy of our accepted branchless pair-distance variant and all
// inherited source citations below.
// Approach:
// A segment-tree leaf whose two endpoint IDs match has LCA(v,v)=v.
// Compute its score directly as 2*(item.w-dis[v]), avoiding two sparse-table
// loads and dependent depth and distance reads. Other leaves use the
// unchanged exact LCA formula.
// Purpose:
// Experimental judged measurement of the singleton-leaf fast path.
// References:
// [1] duck.ac user saffah_cc_v41_agg1, submission #104110:
// https://duck.ac/submission/104110
// Direct copy of its accepted tree-centre engine and inherited
// citations below; no separate license notice was displayed.
// Approach:
// In the hot pair-distance function, use the generic LCA formula for
// every group, including zero-weight groups where the LCA distance is
// exactly zero. This removes one per-call branch without changing answers.
// Purpose:
// Experimental judged measurement of branch removal on the current engine.
// ===== REFERENCES =====
// [1] duck.ac 用户 saffah_cc_v41_260924,提交 #104030 <https://duck.ac/submission/104030>
// (noi18e 新版榜首,367.022875 ms);抓取件 problems/noi18e/ref2/rival_104030.cpp。
// 用途:基底之一 —— 该提交相对其上一代 #103818 <https://duck.ac/submission/103818>
// 只有 42 行(insert 无分支 max、merge_tr 删 pushup、wipe 删 pushup + 短路)。
// [2] duck.ac 用户 saffah_cc_v41_agg1,提交 #103923 <https://duck.ac/submission/103923>
// (372.946573 ms,`problems/noi18e/work/e18_repl_c0.cpp`,**本发的直接基线**)。
// 该复刻件含本工作区此前的两把刀:删死数组 `lg_`,以及"全零边权组"的精确退化快路径(`--c0`)。
// [3] duck.ac 用户 saffah_cc_v41_260924,提交 #103818 / #98940 / #98232 / #89034
// <https://duck.ac/submission/103818> <https://duck.ac/submission/98940>
// <https://duck.ac/submission/98232> <https://duck.ac/submission/89034>:本题算法主干
// (32 B 自有区间最大值线段树节点、迭代式 ins、Item 内联 first_[v] 的 lcadis、
// 链特化 solve_chain 的两棵区间最大值线段树、六数组 u16 化),经 [1][2] 继承。
// 上述公开提交均未附许可证声明;按本工作区惯例注明账号、原始提交地址与所用内容。
// ======================
// ===== 思路 =====
// 本发 = **(A) 复刻 [1] 的 42 行** + **(B) 一把新的单变量:链路径的 `trN` 从线段树换成 Fenwick 最大值树**。
//
// (A) 复刻(§2.16 标准流程),三处微优化:
// (i) `insert` 下降途中的 `if (f2 > pool[o].mf) pool[o].mf = f2;` 改成先在局部做无分支 max 再回写;
// (ii) `merge_tr` 里**删掉 `pushup(a)`**:`mf/mg` 是键区间上的最大值、并集下单调 ⇒
// `pool[a].mf = max(两个孩子 mf)` 就等于 `max(更新前的 a.mf, b.mf)`,先把两个孩子存进局部变量、
// 递归之后再 max 一次即可([1] 注释原话 "pure deletion");
// (iii) `wipe` 删掉 `pushup(o)`(用幸存的 e/f 孩子直接算 mf/mg),并对 `K <= mid` 加短路。
//
// (B) 新刀:`solve_chain` 里 `trN` 只被两种操作触及 ——
// `point_max(trN, yq, wq)`(**只增**地写位置 yq)与 `range_max(trN, yq, n, base)`(**后缀**最大值)。
// **把下标反转**之后后缀最大值就是**前缀最大值**,于是可以用 **Fenwick 最大值树**,
// 两种操作都只要 ~log/2 次访存(线段树是查询 ~2·log、更新 ~log):
// `asuf_upd(p,v)`: `for (i = bnN-p; i <= bnN; i += i&-i) { if (bitN[i] >= v) break; bitN[i] = v; }`
// —— **早退合法**:更新路径上的结点区间**嵌套递增**,前一结点的 max ≥ v ⇒ 其后所有结点也 ≥ v。
// `asuf_qry(p)`: `for (i = bnN-p; i > 0; i -= i&-i)` 取 max。
// 顺带把每组的清零从 `2*base` 降到 `bnN = n+1`(n = 5e4 时 131072 → 50001 次写)。
// `trC` 的查询是**一般区间** [xq+1, yq],Fenwick 做不了 ⇒ **线段树保持不动**。
// 语义逐位等价:同样的 NINF 哨兵、同样的"只增"更新、同样的 [yq, n] 区间、同样的取值顺序。
// 正确性:本地 rt / chainrt / czerort / mixc0rt 四套对拍全部 0 mismatch(交前跑)。
// ================
#ifdef LOCAL_TEST
#include <cstdio>
#endif
#ifdef DBG
#include <cstdio>
#endif
#if defined(LOCAL_TEST) || defined(DBG)
#include <cstdio>
#include <cstdlib>
#include <cstring>
typedef unsigned long long u64;
static char g_in[48 << 20];
static char g_out[8 << 20];
#else
typedef unsigned long long u64;
#endif
typedef long long i64;
typedef unsigned int u32;
#define MAXN 50005
#define MAXM 100005
#define MAXE 100005
#define MAXIT 200010
#define MAXPOOL 3600005
#define LG 18
static const i64 NINF = -(i64)1 << 60;
// ---------------- tree ----------------
static u32 head_[MAXN + 2];
static unsigned short eto[MAXE]; static u32 ew[MAXE];
static unsigned short par_[MAXN], dep_[MAXN], pre_[MAXN];
static i64 dis_[MAXN];
static unsigned short euler[2 * MAXN];
static u32 first_[MAXN]; // Euler POSITION (<=2n-1=100009) needs 17 bits: stays u32
// Sixteen-entry Euler blocks: packed depth+node prefix/suffix minima and
// a sparse table over the block minima, about 1.2 MB in total.
#define RMQB 4
#define RMQRS 2
#define RMQNB ((2 * MAXN + RMQB - 1) / RMQB)
static u32 rmq_pref[2 * MAXN], rmq_suf[2 * MAXN];
static u32 rmq_st[15][RMQNB];
static inline u32 rmq_pack(u32 v) { return ((u32)dep_[v] << 16) | v; }
static inline u32 rmq_pick(u32 a, u32 b) { return (a >> 16) < (b >> 16) ? a : b; }
static inline u32 rmq_query(u32 l, u32 r) {
if (l > r) { u32 z=l; l=r; r=z; }
u32 bl=l>>RMQRS, br=r>>RMQRS;
if (bl==br) {
u32 z=rmq_pack(euler[l]);
for (u32 j=l+1;j<=r;j++) z=rmq_pick(z,rmq_pack(euler[j]));
return z;
}
u32 z=rmq_pick(rmq_suf[l],rmq_pref[r]);
if (bl+1<br) {
u32 L=bl+1, R=br-1, len=R-L+1;
u32 k=31u-(u32)__builtin_clz(len);
z=rmq_pick(z,rmq_pick(rmq_st[k][L],rmq_st[k][R-(1u<<k)+1]));
}
return z;
}
static unsigned short ord_[MAXN];
static int g_c0; // 1 <=> every c_i of this group is 0
static int g_chain; // 1 <=> the tree is the literal chain 1-2-...-n
static inline int lca_of(int u, int v) { // node identity, used once per path
return (int)(rmq_query(first_[u],first_[v]) & 0xffffu);
}
// hot path: the callers only need dis[lca], never which node it is. Takes the two
// Euler first-occurrence positions straight out of the item (no first_[] load).
static inline i64 lcadis(u32 fu, u32 fv) {
return dis_[rmq_query(fu,fv) & 0xffffu];
}
// ---------------- items (32B, self-contained for cache) ----------------
struct Item { u32 v; u32 fv; i64 w, f2, g2; }; // fv = first_[v]; w = dis[v] + w
static Item itm[MAXIT];
static u32 phead[MAXN], pnxt[MAXIT];
static u32 pkey[MAXIT], ppt[MAXIT];
static int g_key1; /* 1 <=> every item's pkey == 1 (subtask S2) */
// ---------------- segment tree ----------------
// own (mf,mg) = max f2/g2 over the key range; e,f = children (leaf: item ids).
// 32B aligned => one node is always inside one cache line.
struct TNode { i64 mf, mg; u32 e, f; } __attribute__((aligned(32)));
static TNode pool[MAXPOOL];
static u32 pool_n;
static i64 ans;
static inline i64 calc(int x, int y) { // itm[].w already carries dis[v]
return itm[x].w + itm[y].w - 2 * lcadis(itm[x].fv, itm[y].fv);
}
static void pushup(u32 o) {
u32 l = pool[o].e, r = pool[o].f;
i64 f = NINF, g = NINF;
if (l) { i64 x = pool[l].mf; if (x > f) f = x; x = pool[l].mg; if (x > g) g = x; }
if (r) { i64 x = pool[r].mf; if (x > f) f = x; x = pool[r].mg; if (x > g) g = x; }
pool[o].mf = f; pool[o].mg = g;
}
static inline i64 leafval(u32 o) {
u32 x = pool[o].e, y = pool[o].f;
if (x == y) return 2 * (itm[x].w - dis_[itm[x].v]); // LCA(v,v)=v
return calc((int)x, (int)y);
}
static void leaf_combine(u32 a, u32 b, i64 deep2) {
int ax = (int)pool[a].e, ay = (int)pool[a].f;
int bx = (int)pool[b].e, by = (int)pool[b].f;
i64 best = NINF, cross = NINF;
int rx = 0, ry = 0;
{ i64 v = leafval(a); best = v; rx = ax; ry = ay; }
{ i64 v = leafval(b); if (v > best) { best = v; rx = bx; ry = by; } }
if (ax) {
if (bx) { i64 v = calc(ax, bx); if (v > best) { best = v; rx = ax; ry = bx; } if (v > cross) cross = v; }
if (by) { i64 v = calc(ax, by); if (v > best) { best = v; rx = ax; ry = by; } if (v > cross) cross = v; }
}
if (ay) {
if (bx) { i64 v = calc(ay, bx); if (v > best) { best = v; rx = ay; ry = bx; } if (v > cross) cross = v; }
if (by) { i64 v = calc(ay, by); if (v > best) { best = v; rx = ay; ry = by; } if (v > cross) cross = v; }
}
if (pool[b].mf > pool[a].mf) pool[a].mf = pool[b].mf;
if (pool[b].mg > pool[a].mg) pool[a].mg = pool[b].mg;
pool[a].e = (u32)rx; pool[a].f = (u32)ry;
if (cross != NINF) { i64 t = cross - deep2; if (t > ans) ans = t; }
}
// Iterative insert. With a node now storing its OWN range maxes, inserting one item
// changes every node on the root-to-leaf path by exactly max(old, f2) / max(old, g2) --
// so the recursion AND all 1.2M pushup calls in this path disappear.
static u32 ins(u32 o, int l, int r, int pos, int pt, i64 deep2) {
i64 f2 = itm[pt].f2, g2 = itm[pt].g2;
u32 root = o, *link = &root;
int lo = l, hi = r;
while (lo < hi) {
if (!o) {
o = ++pool_n;
pool[o].e = 0; pool[o].f = 0;
pool[o].mf = f2; pool[o].mg = g2;
*link = o;
} else {
{ i64 nf = pool[o].mf; nf = f2 > nf ? f2 : nf;
i64 ng = pool[o].mg; ng = g2 > ng ? g2 : ng;
pool[o].mf = nf; pool[o].mg = ng; }
}
int mid = (lo + hi) >> 1;
if (pos <= mid) {
u32 rc = pool[o].f; // sibling's right half is deeper
if (rc) { i64 v = f2 + pool[rc].mg - deep2; if (v > ans) ans = v; }
link = &pool[o].e; o = pool[o].e; hi = mid;
} else {
u32 lc = pool[o].e; // this item is the deeper one
if (lc) { i64 v = pool[lc].mf + g2 - deep2; if (v > ans) ans = v; }
link = &pool[o].f; o = pool[o].f; lo = mid + 1;
}
}
if (!o) { // leaf at lo == hi == pos, first item in it
o = ++pool_n;
pool[o].e = (u32)pt; pool[o].f = (u32)pt;
pool[o].mf = f2; pool[o].mg = g2;
*link = o;
return root;
}
if (f2 > pool[o].mf) pool[o].mf = f2;
if (g2 > pool[o].mg) pool[o].mg = g2;
u32 x = pool[o].e, y = pool[o].f;
if (!x) { pool[o].e = pool[o].f = (u32)pt; return root; }
i64 v1 = calc(pt, (int)x), v2 = (x == y) ? v1 : calc(pt, (int)y);
i64 v = v1 > v2 ? v1 : v2;
{ i64 t = v - deep2; if (t > ans) ans = t; }
i64 v0 = leafval(o);
if (v0 >= v1 && v0 >= v2) return root;
if (v1 >= v2) pool[o].f = (u32)pt; else pool[o].e = (u32)pt;
return root;
}
static u32 merge_tr(u32 a, u32 b, int l, int r, i64 deep2) {
if (!a) return b;
if (!b) return a;
if (l == r) { leaf_combine(a, b, deep2); return a; }
int mid = (l + r) >> 1;
u32 al = pool[a].e, ar = pool[a].f, bl = pool[b].e, br = pool[b].f;
i64 amf0 = pool[a].mf, amg0 = pool[a].mg, bmf0 = pool[b].mf, bmg0 = pool[b].mg;
{ i64 am = al ? pool[al].mf : NINF;
if (am != NINF) { i64 v = am + (br ? pool[br].mg : NINF) - deep2; if (v > ans) ans = v; }
i64 bm = bl ? pool[bl].mf : NINF;
if (bm != NINF) { i64 v = bm + (ar ? pool[ar].mg : NINF) - deep2; if (v > ans) ans = v; } }
if (al) __builtin_prefetch(&pool[al], 1, 3);
if (ar) __builtin_prefetch(&pool[ar], 1, 3);
if (bl) __builtin_prefetch(&pool[bl], 1, 3);
if (br) __builtin_prefetch(&pool[br], 1, 3);
pool[a].e = merge_tr(al, bl, l, mid, deep2);
pool[a].f = merge_tr(ar, br, mid + 1, r, deep2);
pool[a].mf = amf0 > bmf0 ? amf0 : bmf0;
pool[a].mg = amg0 > bmg0 ? amg0 : bmg0;
return a;
}
// keys > K never occur (presence rule), so clearing key K is enough; but the range
// version below is equivalent and simpler to keep exact.
static u32 wipe(u32 o, int l, int r, int K) {
if (!o || r < K) return o;
if (l >= K) return 0;
int mid = (l + r) >> 1;
if (K <= mid) {
u32 c0 = wipe(pool[o].e, l, mid, K);
if (!c0) return 0;
pool[o].e = c0; pool[o].f = 0;
pool[o].mf = pool[c0].mf; pool[o].mg = pool[c0].mg;
return o;
}
u32 c0 = pool[o].e;
u32 c1 = wipe(pool[o].f, mid + 1, r, K);
pool[o].f = c1;
if (!c1) {
if (!c0) return 0;
pool[o].mf = pool[c0].mf; pool[o].mg = pool[c0].mg;
return o;
}
i64 f = pool[c1].mf, g = pool[c1].mg;
if (c0) { i64 x = pool[c0].mf; if (x > f) f = x; x = pool[c0].mg; if (x > g) g = x; }
pool[o].mf = f; pool[o].mg = g;
return o;
}
// ---------------- io ----------------
#ifdef LOCAL_TEST
static const unsigned char *ip_, *ie_;
static char *op_;
#else
struct DI {
u64 abi;
const char *s; u64 sn;
char *o; u64 ol; u64 os;
char *e; u64 el; u64 es;
const char *IB; u64 IBl;
char *OB; u64 OBl;
u64 tsc;
} __attribute__((packed));
static DI *D;
static const unsigned char *ip_, *ie_;
static char *op_;
#endif
static inline i64 nll() {
const unsigned char *p = ip_;
while (*p <= ' ') p++;
i64 v = 0;
while (*p > ' ') { v = v * 10 + (i64)(*p - '0'); p++; }
ip_ = p;
return v;
}
static inline int ni() { return (int)nll(); }
static inline void pc(char c) { *op_++ = c; }
static inline void pll(i64 v) {
char t[24]; int q = 0;
if (v < 0) { pc('-'); v = -v; }
if (!v) t[q++] = '0';
while (v) { t[q++] = (char)('0' + (int)(v % 10)); v /= 10; }
while (q) pc(t[--q]);
}
// ---------------- chain specialist (a_i = b_i - 1) ----------------
#define MAXS 131072
static u32 cw_[MAXN + 2];
static i64 dis2_[MAXN + 2];
static u32 ox[MAXM], oy[MAXM], ord2[MAXM + 1], cstart[MAXN + 3];
static i64 ow[MAXM];
static i64 trC[2 * MAXS];
// trN has exactly two operations: "increase the value at p" and "max over [p, n]". Reversing
// the index turns the suffix query into a prefix max, so a Fenwick max tree gives both in
// ~log/2 probes instead of the segment tree's ~2*log (query) / ~log (update); the per-group
// clear also drops from 2*base to bnN = n+1.
static i64 bitN[MAXS + 2];
static int bnN;
static inline i64 asuf_qry(int p) {
i64 res = NINF;
for (int i = bnN - p; i > 0; i -= i & -i) { i64 t = bitN[i]; if (t > res) res = t; }
return res;
}
static inline void asuf_upd(int p, i64 v) {
for (int i = bnN - p; i <= bnN; i += i & -i) { if (bitN[i] >= v) break; bitN[i] = v; }
}
static i64 range_max(const i64 *tr, int l, int r, int base) {
i64 res = NINF;
if (l > r) return res;
int lo = base + l, hi = base + r + 1;
while (lo < hi) {
if (lo & 1) { if (tr[lo] > res) res = tr[lo]; lo++; }
if (hi & 1) { hi--; if (tr[hi] > res) res = tr[hi]; }
lo >>= 1; hi >>= 1;
}
return res;
}
static void point_max(i64 *tr, int p, i64 v, int base) {
int i = base + p;
if (tr[i] >= v) return;
tr[i] = v;
i >>= 1;
while (i) {
i64 a = tr[2 * i], b = tr[2 * i + 1];
i64 mx = a > b ? a : b;
if (tr[i] == mx) break;
tr[i] = mx;
i >>= 1;
}
}
static void solve_chain(int n, const u32 *ea, const u32 *ec) {
for (int i = 0; i < n - 1; i++) cw_[ea[i]] = ec[i];
dis2_[1] = 0;
for (int v = 2; v <= n; v++) dis2_[v] = dis2_[v - 1] + (i64)cw_[v - 1];
int m = ni();
int cnt = 0;
for (int i = 0; i < m; i++) {
int x = ni(), y = ni();
i64 v = nll();
if (x == y) continue; // covers no edge -> can never share one
if (x > y) { int t = x; x = y; y = t; }
ox[cnt] = (u32)x; oy[cnt] = (u32)y;
ow[cnt] = (dis2_[y] - dis2_[x]) - v;
cnt++;
}
if (cnt < 2) { pc('F'); pc('\n'); return; }
int base = 1;
while (base <= n) base <<= 1;
for (int i = 0; i < 2 * base; i++) trC[i] = NINF;
bnN = n + 1;
for (int i = 1; i <= bnN; i++) bitN[i] = NINF;
for (int i = 0; i <= n + 1; i++) cstart[i] = 0;
for (int i = 0; i < cnt; i++) cstart[ox[i]]++;
{ u32 s = 0;
for (int i = 0; i <= n + 1; i++) { u32 c = cstart[i]; cstart[i] = s; s += c; } }
for (int i = 0; i < cnt; i++) ord2[cstart[ox[i]]++] = (u32)i;
i64 best = NINF;
for (int k = 0; k < cnt; k++) {
int qi = (int)ord2[k];
int xq = (int)ox[qi], yq = (int)oy[qi];
i64 wq = ow[qi];
{ i64 a = range_max(trC, xq + 1, yq, base);
if (a > NINF / 2) { i64 t = a + wq + dis2_[xq]; if (t > best) best = t; } }
{ i64 b = asuf_qry(yq);
if (b > NINF / 2) { i64 t = b - (dis2_[yq] - dis2_[xq] - wq); if (t > best) best = t; } }
point_max(trC, yq, wq - dis2_[yq], base);
asuf_upd(yq, wq);
}
if (best <= NINF / 2) { pc('F'); } else pll(best);
pc('\n');
}
/* ==== S2 fast path (ported from work/n18y_s2patch.py, adapted by b18e_) ==== */
static u32 s2_ins(u32 o, int pt, i64 deep2) {
i64 f2 = itm[pt].f2, g2 = itm[pt].g2;
if (!o) {
o = ++pool_n;
pool[o].e = (u32)pt; pool[o].f = (u32)pt; pool[o].mf = f2; pool[o].mg = g2;
return o;
}
if (f2 > pool[o].mf) pool[o].mf = f2;
if (g2 > pool[o].mg) pool[o].mg = g2;
u32 x = pool[o].e, y = pool[o].f;
if (!x) { pool[o].e = pool[o].f = (u32)pt; return o; }
i64 v1 = calc(pt, (int)x), v2 = (x == y) ? v1 : calc(pt, (int)y);
i64 v = v1 > v2 ? v1 : v2;
{ i64 z = v - deep2; if (z > ans) ans = z; }
i64 v0 = leafval(o);
if (v0 >= v1 && v0 >= v2) return o;
if (v1 >= v2) pool[o].f = (u32)pt; else pool[o].e = (u32)pt;
return o;
}
static u32 s2_merge(u32 a, u32 b, i64 deep2) {
if (!a) return b;
if (!b) return a;
leaf_combine(a, b, deep2);
return a;
}
static void solve_group() {
int n = ni();
static u32 deg[MAXN + 2];
for (int i = 1; i <= n; i++) deg[i] = 0;
static u32 ea[MAXN], eb[MAXN], ec[MAXN];
g_chain = 1;
g_c0 = 1;
for (int i = 0; i < n - 1; i++) {
int a = ni(), b = ni(), c = ni();
if (b != a + 1) g_chain = 0;
if (c) g_c0 = 0;
ea[i] = a; eb[i] = b; ec[i] = c;
deg[a]++; deg[b]++;
}
if (g_chain) { solve_chain(n, ea, ec); return; }
{
u32 s = 0;
for (int i = 1; i <= n; i++) { head_[i] = s; s += deg[i]; }
head_[n + 1] = s;
}
{
static u32 pos[MAXN + 2];
for (int i = 1; i <= n; i++) pos[i] = head_[i];
for (int i = 0; i < n - 1; i++) {
u32 a = ea[i], b = eb[i], c = ec[i];
eto[pos[a]] = b; ew[pos[a]++] = c;
eto[pos[b]] = a; ew[pos[b]++] = c;
}
}
{
int top = 0;
static u32 stk[MAXN], ptr[MAXN];
par_[1] = 0; dep_[1] = 0; dis_[1] = 0;
stk[0] = 1; ptr[1] = head_[1];
int ec_ = 0, pc_ = 0;
euler[ec_] = 1; first_[1] = ec_; ec_++;
pre_[pc_++] = 1;
while (top >= 0) {
u32 u = stk[top];
if (ptr[u] < head_[u + 1]) {
u32 idx = ptr[u]++;
u32 v = eto[idx];
if (v == par_[u]) continue;
par_[v] = u; dep_[v] = dep_[u] + 1; dis_[v] = dis_[u] + ew[idx];
first_[v] = ec_; euler[ec_] = v; ec_++;
if (pc_ < n) pre_[pc_++] = v;
stk[++top] = v; ptr[v] = head_[v];
} else {
top--;
if (top >= 0) { euler[ec_] = stk[top]; ec_++; }
}
}
}
{
int m_ = 2 * n - 1;
if (!g_chain) {
int nb=(m_+RMQB-1)/RMQB;
for (int b=0;b<nb;b++) {
int l=b*RMQB, r=l+RMQB; if(r>m_)r=m_;
u32 z=0;
for (int i=l;i<r;i++) { u32 p=rmq_pack(euler[i]); z=(i==l)?p:rmq_pick(z,p); rmq_pref[i]=z; }
for (int i=r-1;i>=l;i--) { u32 p=rmq_pack(euler[i]); z=(i==r-1)?p:rmq_pick(p,z); rmq_suf[i]=z; }
rmq_st[0][b]=rmq_pref[r-1];
}
for (int k=1;(1<<k)<=nb;k++)
for (int b=0;b+(1<<k)<=nb;b++)
rmq_st[k][b]=rmq_pick(rmq_st[k-1][b],rmq_st[k-1][b+(1<<(k-1))]);
}
}
int m = ni();
u32 maxdep = 0;
for (int v = 1; v <= n; v++) if (dep_[v] > maxdep) maxdep = dep_[v];
static u32 tat[MAXIT]; /* pkey/ppt are written directly at the source: the
previous tkey/tpt arrays existed only to be copied
into pkey/ppt by the reverse linked-list pass. */
int nit = 0;
for (int i = 0; i < m; i++) {
int x = ni(), y = ni();
i64 cost = nll();
int anc = lca_of(x, y);
i64 len = dis_[x] + dis_[y] - 2 * dis_[anc];
i64 f2 = 2 * (len - cost);
i64 g2 = f2 + 2 * dis_[anc];
i64 base = len - 2 * cost;
if (x != anc) {
int id = 2 * i + 1;
itm[id].v = (u32)y; itm[id].fv = first_[y];
itm[id].w = base + dis_[x] + dis_[y];
itm[id].f2 = f2; itm[id].g2 = g2;
pkey[nit] = dep_[anc] + 1; tat[nit] = x; ppt[nit] = id;
nit++;
}
if (y != anc) {
int id = 2 * i + 2;
itm[id].v = (u32)x; itm[id].fv = first_[x];
itm[id].w = base + dis_[x] + dis_[y];
itm[id].f2 = f2; itm[id].g2 = g2;
pkey[nit] = dep_[anc] + 1; tat[nit] = y; ppt[nit] = id;
nit++;
}
}
for (int v = 1; v <= n; v++) phead[v] = 0;
for (int e = nit - 1; e >= 0; e--) {
u32 v = tat[e];
pnxt[e] = phead[v]; phead[v] = (u32)(e + 1);
}
for (int i = 0; i < n; i++) ord_[i] = pre_[n - 1 - i];
static u32 rt[MAXN];
for (int v = 1; v <= n; v++) rt[v] = 0;
pool_n = 0;
int S = (int)maxdep + 1; if (S < 1) S = 1;
g_key1 = 1;
for (int e = 0; e < nit; e++) if (pkey[e] != 1) { g_key1 = 0; break; }
ans = NINF;
if (g_key1) { /* ==== S2: one-key domain, single-leaf tree ==== */
for (int oi = 0; oi < n; oi++) {
u32 t = ord_[oi];
i64 deep2 = 2 * dis_[t];
for (u32 c = head_[t]; c < head_[t + 1]; c++) {
u32 v = eto[c];
if (v == par_[t]) continue;
if (!rt[v]) continue;
rt[t] = s2_merge(rt[t], rt[v], deep2);
}
for (u32 e = phead[t]; e; e = pnxt[e - 1]) {
// n18x_: keep the earned two-step itm prefetch (s2_ins still reads random itm[pt])
u32 en = pnxt[e - 1];
if (en) __builtin_prefetch((const void *)&itm[ppt[en - 1]], 0, 3);
u32 en2 = en ? pnxt[en - 1] : 0;
if (en2) __builtin_prefetch((const void *)&itm[ppt[en2 - 1]], 0, 3);
rt[t] = s2_ins(rt[t], (int)ppt[e - 1], deep2);
}
if (rt[t] && (int)dep_[t] <= 1) rt[t] = 0; /* wipe: keys >= K, only key == 1 exists */
}
} else {
for (int oi = 0; oi < n; oi++) {
u32 t = ord_[oi];
i64 deep2 = 2 * dis_[t];
for (u32 c = head_[t]; c < head_[t + 1]; c++) {
u32 v = eto[c];
if (v == par_[t]) continue;
if (!rt[v]) continue;
if (!rt[t]) rt[t] = rt[v];
else rt[t] = merge_tr(rt[t], rt[v], 1, S, deep2);
}
for (u32 e = phead[t]; e; e = pnxt[e - 1]) {
// n18x_: the per-item random load of itm[pt] inside ins() is the #1 profiled cost
// (perf srcline 19.5% on the `itm[pt].f2/g2` line). Issue the next item's line early.
u32 en = pnxt[e - 1];
if (en) __builtin_prefetch((const void *)&itm[ppt[en - 1]], 0, 3);
u32 en2 = en ? pnxt[en - 1] : 0;
if (en2) __builtin_prefetch((const void *)&itm[ppt[en2 - 1]], 0, 1);
rt[t] = ins(rt[t], 1, S, (int)pkey[e - 1], (int)ppt[e - 1], deep2);
}
if (rt[t]) rt[t] = wipe(rt[t], 1, S, (int)dep_[t]);
}
}
if (ans <= NINF / 2) { pc('F'); }
else pll(ans >> 1);
pc('\n');
}
static void main_solve() {
int T = ni();
while (T--) solve_group();
}
#ifdef LOCAL_TEST
int main() {
size_t sn = fread(g_in, 1, sizeof(g_in), stdin);
ip_ = (const unsigned char *)g_in; ie_ = ip_ + sn;
op_ = g_out;
main_solve();
fwrite(g_out, 1, (size_t)(op_ - g_out), stdout);
return 0;
}
#else
int main() { return 0; }
extern "C" void __libc_start_main(void *mm, int argc, char **argv) {
(void)mm;
unsigned long *p = (unsigned long *)(argv + argc + 1);
while (*p) p++;
p++;
for (; p[0]; p += 2) if (p[0] == 0x6b637564UL) { D = (DI *)p[1]; break; }
if (D) {
ip_ = (const unsigned char *)D->s; ie_ = ip_ + D->sn; op_ = D->o;
main_solve();
D->os = (u64)(op_ - D->o);
}
__asm__ volatile("syscall" ::"a"(60), "D"(0) : "rcx", "r11", "memory");
for (;;);
}
#endif
| Compilation | N/A | N/A | Compile OK | Score: N/A | 显示更多 |
| Testcase #1 | 13.77 us | 68 KB | Accepted | Score: 5 | 显示更多 |
| Testcase #2 | 141.39 us | 132 KB | Accepted | Score: 5 | 显示更多 |
| Testcase #3 | 1.808 ms | 212 KB | Accepted | Score: 5 | 显示更多 |
| Testcase #4 | 9.038 ms | 160 KB | Accepted | Score: 5 | 显示更多 |
| Testcase #5 | 159.048 ms | 1 MB + 272 KB | Accepted | Score: 5 | 显示更多 |
| Testcase #6 | 260.93 ms | 4 MB + 856 KB | Accepted | Score: 5 | 显示更多 |
| Testcase #7 | 154.066 ms | 5 MB + 348 KB | Accepted | Score: 5 | 显示更多 |
| Testcase #8 | 293.107 ms | 21 MB + 68 KB | Accepted | Score: 5 | 显示更多 |
| Testcase #9 | 296.96 ms | 20 MB + 472 KB | Accepted | Score: 5 | 显示更多 |
| Testcase #10 | 80.705 ms | 3 MB + 464 KB | Accepted | Score: 5 | 显示更多 |
| Testcase #11 | 168.839 ms | 17 MB + 708 KB | Accepted | Score: 5 | 显示更多 |
| Testcase #12 | 177.027 ms | 17 MB + 340 KB | Accepted | Score: 5 | 显示更多 |
| Testcase #13 | 110.695 ms | 3 MB + 760 KB | Accepted | Score: 5 | 显示更多 |
| Testcase #14 | 110.403 ms | 3 MB + 732 KB | Accepted | Score: 5 | 显示更多 |
| Testcase #15 | 227.121 ms | 14 MB + 524 KB | Accepted | Score: 5 | 显示更多 |
| Testcase #16 | 214.691 ms | 14 MB + 140 KB | Accepted | Score: 5 | 显示更多 |
| Testcase #17 | 151.289 ms | 5 MB + 616 KB | Accepted | Score: 5 | 显示更多 |
| Testcase #18 | 289.975 ms | 20 MB + 436 KB | Accepted | Score: 5 | 显示更多 |
| Testcase #19 | 252.748 ms | 23 MB + 184 KB | Accepted | Score: 5 | 显示更多 |
| Testcase #20 | 246.504 ms | 20 MB + 408 KB | Accepted | Score: 5 | 显示更多 |