\(\mathcal{Description}\)

  给定一棵 \(n\) 个点的带点权树,\(q\) 次操作:

  • 路径点权赋值。
  • 询问路径最大子段和(可以为空)。

  \(n,q\le10^5\)。

\(\mathcal{Solution}\)

  嘛……其实就是 GSS3 搬到树上 qwq。应该可以熟练地列出转移矩阵了叭,设 \(f(u)\) 为以 \(u\) 为端点的最大子段和,\(g(u)\) 为前缀最大子段和,\(s_u\) 为 \(u\) 的重儿子(这题来练练树剖 www),有:

\[\begin{bmatrix}g(u)\\f(u)\\0\end{bmatrix}=\begin{bmatrix}0&a_u&0\\-\infty&a_u&0\\-\infty&-\infty&0\end{bmatrix}\begin{bmatrix}g(s_u)\\f(s_u)\\0\end{bmatrix}
\]

  注意在树剖跳重链求答案的时候,必须注意矩乘顺序。例如对于路径 \((u,v)\),钦定 \(u\) 为路径起点,当 \(u\) 向上跳时,转移矩阵按 DFN 降序;当 \(v\) 向上跳时转移矩阵按 DFN 升序,所以线段树应维护两个乘法顺序的矩阵积。

  这道题有些卡常(而且我常数貌似很大 qwq),所以手玩一下转移矩阵的幂,发现:

\[\begin{bmatrix}0&v&-\infty\\-\infty&v&0\\-\infty&-\infty&0\end{bmatrix}^k=\begin{bmatrix}0&\max\{v,kv\}&\max\{0,kv\}\\-\infty&kv&\max\{0,kv\}\\-\infty&-\infty&0\end{bmatrix}
\]

  就可以 \(\mathcal O(1)\) 求出矩阵幂了。

\(\mathcal{Code}\)

  虽然长,但我觉得代码颜值挺高的 www。(大雾

  1. #include <cstdio>
  2. # ifdef LOCAL_DEBUG
  3. const int MAXN = 5;
  4. # else
  5. const int MAXN = 1e5;
  6. # endif
  7. const int NINF = -( 1ll << 30 );
  8. int n, m, ecnt, a[MAXN + 5], head[MAXN + 5];
  9. int fa[MAXN + 5], dep[MAXN + 5], siz[MAXN + 5], son[MAXN + 5];
  10. int dfc, dfn[MAXN + 5], ref[MAXN + 5], top[MAXN + 5];
  11. inline int max_ ( const int a, const int b ) { return a > b ? a : b; }
  12. inline char fgc () {
  13. static char buf[1 << 17], *p = buf, *q = buf;
  14. return p == q && ( q = buf + fread ( p = buf, 1, 1 << 17, stdin ), p == q ) ? EOF : *p ++;
  15. }
  16. inline int rint () {
  17. # ifdef LOCAL_DEBUG
  18. # define fgc getchar
  19. # endif
  20. int x = 0, f = 1; char s = fgc ();
  21. for ( ; s < '0' || '9' < s; s = fgc () ) f = s == '-' ? -f : f;
  22. for ( ; '0' <= s && s <= '9'; s = fgc () ) x = x * 10 + ( s ^ '0' );
  23. return x * f;
  24. }
  25. inline void wint ( int x ) {
  26. if ( x < 0 ) putchar ( '-' ), x = -x;
  27. if ( 9 < x ) wint ( x / 10 );
  28. putchar ( x % 10 ^ '0' );
  29. }
  30. struct Edge { int to, nxt; } graph[MAXN * 2 + 5];
  31. inline void link ( const int s, const int t ) {
  32. graph[++ ecnt] = { t, head[s] };
  33. head[s] = ecnt;
  34. }
  35. struct Matrix {
  36. int mat[3][3];
  37. Matrix (): mat { NINF, NINF, NINF, NINF, NINF, NINF, NINF, NINF, NINF } {}
  38. inline int* operator [] ( const int key ) { return mat[key]; }
  39. inline Matrix operator * ( Matrix t ) {
  40. Matrix ret;
  41. for ( int i = 0; i < 3; ++ i ) {
  42. for ( int k = 0; k < 3; ++ k ) {
  43. for ( int j = 0; j < 3; ++ j ) {
  44. ret[i][j] = max_ ( ret[i][j], mat[i][k] + t[k][j] );
  45. }
  46. }
  47. }
  48. return ret;
  49. }
  50. };
  51. inline Matrix identity () {
  52. static Matrix I;
  53. I[0][0] = I[1][1] = I[2][2] = 0;
  54. return I;
  55. }
  56. inline Matrix make ( const int v ) {
  57. Matrix A;
  58. A[0][0] = A[0][2] = A[1][2] = A[2][2] = 0;
  59. A[0][1] = A[1][1] = v;
  60. return A;
  61. }
  62. inline Matrix power ( const int v, const int k ) {
  63. Matrix A;
  64. A[0][0] = A[2][2] = 0;
  65. A[0][1] = max_ ( v, k * v );
  66. A[0][2] = A[1][2] = max_ ( 0, k * v );
  67. A[1][1] = k * v;
  68. return A;
  69. }
  70. struct SegmentTree {
  71. Matrix S[2][MAXN * 2 + 5]; int tag[MAXN * 2 + 5];
  72. inline int id ( const int l, const int r ) { return ( l + r ) | ( l != r ); }
  73. inline void pushup ( const int l, const int r ) {
  74. int rt = id ( l, r ), mid = l + r >> 1, lc = id ( l, mid ), rc = id ( mid + 1, r );
  75. S[0][rt] = S[0][lc] * S[0][rc], S[1][rt] = S[1][rc] * S[1][lc];
  76. }
  77. inline void pushas ( const int l, const int r, const int v ) {
  78. int rt = id ( l, r );
  79. S[0][rt] = S[1][rt] = power ( v, r - l + 1 ), tag[rt] = v;
  80. }
  81. inline void pushdn ( const int l, const int r ) {
  82. int rt = id ( l, r ), mid = l + r >> 1;
  83. if ( tag[rt] == NINF ) return ;
  84. pushas ( l, mid, tag[rt] ), pushas ( mid + 1, r, tag[rt] );
  85. tag[rt] = NINF;
  86. }
  87. inline void build ( const int l, const int r ) {
  88. int rt = id ( l, r ), mid = l + r >> 1;
  89. tag[rt] = NINF;
  90. if ( l == r ) return void ( S[0][rt] = S[1][rt] = make ( a[ref[l]] ) );
  91. build ( l, mid ), build ( mid + 1, r );
  92. pushup ( l, r );
  93. }
  94. inline void assign ( const int l, const int r, const int al, const int ar, const int v ) {
  95. int mid = l + r >> 1;
  96. if ( al <= l && r <= ar ) return pushas ( l, r, v );
  97. pushdn ( l, r );
  98. if ( al <= mid ) assign ( l, mid, al, ar, v );
  99. if ( mid < ar ) assign ( mid + 1, r, al, ar, v );
  100. pushup ( l, r );
  101. }
  102. inline Matrix query ( const int l, const int r, const int ql, const int qr, const bool type ) {
  103. int rt = id ( l, r ), mid = l + r >> 1;
  104. if ( ql <= l && r <= qr ) return S[type][rt];
  105. pushdn ( l, r );
  106. if ( qr <= mid ) return query ( l, mid, ql, qr, type );
  107. else if ( mid < ql ) return query ( mid + 1, r, ql, qr, type );
  108. else return ! type ?
  109. query ( l, mid, ql, qr, 0 ) * query ( mid + 1, r, ql, qr, 0 ):
  110. query ( mid + 1, r, ql, qr, 1 ) * query ( l, mid, ql, qr, 1 );
  111. }
  112. } st;
  113. inline void DFS1 ( const int u, const int f ) {
  114. dep[u] = dep[fa[u] = f] + ( siz[u] = 1 );
  115. for ( int i = head[u], v; i; i = graph[i].nxt ) {
  116. if ( ( v = graph[i].to ) ^ f ) {
  117. DFS1 ( v, u ), siz[u] += siz[v];
  118. if ( siz[son[u]] < siz[v] ) son[u] = v;
  119. }
  120. }
  121. }
  122. inline void DFS2 ( const int u, const int tp ) {
  123. ref[dfn[u] = ++ dfc] = u, top[u] = tp;
  124. if ( son[u] ) DFS2 ( son[u], tp );
  125. for ( int i = head[u], v; i; i = graph[i].nxt ) {
  126. if ( ( v = graph[i].to ) ^ fa[u] && v ^ son[u] ) {
  127. DFS2 ( v, v );
  128. }
  129. }
  130. }
  131. inline void assignChain ( int u, int v, const int w ) {
  132. while ( top[u] ^ top[v] ) {
  133. if ( dep[top[u]] < dep[top[v]] ) u ^= v ^= u ^= v;
  134. st.assign ( 1, n, dfn[top[u]], dfn[u], w );
  135. u = fa[top[u]];
  136. }
  137. if ( dep[u] < dep[v] ) u ^= v ^= u ^= v;
  138. st.assign ( 1, n, dfn[v], dfn[u], w );
  139. }
  140. inline int queryChain ( int u, int v ) {
  141. Matrix A ( identity () ), B ( identity () );
  142. while ( top[u] ^ top[v] ) {
  143. if ( dep[top[u]] < dep[top[v]] ) {
  144. B = st.query ( 1, n, dfn[top[v]], dfn[v], 0 ) * B;
  145. v = fa[top[v]];
  146. } else {
  147. A = A * st.query ( 1, n, dfn[top[u]], dfn[u], 1 );
  148. u = fa[top[u]];
  149. }
  150. }
  151. if ( dep[u] > dep[v] ) A = A * st.query ( 1, n, dfn[v], dfn[u], 1 );
  152. else B = st.query ( 1, n, dfn[u], dfn[v], 0 ) * B;
  153. A = A * B;
  154. return max_ ( A[0][1], A[0][2] );
  155. }
  156. int main () {
  157. n = rint ();
  158. for ( int i = 1; i <= n; ++ i ) a[i] = rint ();
  159. for ( int i = 1, u, v; i < n; ++ i ) {
  160. u = rint (), v = rint ();
  161. link ( u, v ), link ( v, u );
  162. }
  163. DFS1 ( 1, 0 ), DFS2 ( 1, 1 );
  164. st.build ( 1, n );
  165. for ( int q = rint (), op, a, b, c; q --; ) {
  166. op = rint (), a = rint (), b = rint ();
  167. if ( op & 1 ) {
  168. wint ( queryChain ( a, b ) );
  169. putchar ( '\n' );
  170. } else {
  171. c = rint ();
  172. assignChain ( a, b, c );
  173. }
  174. }
  175. return 0;
  176. }

Solution -「SP 6779」GSS7的更多相关文章

  1. Solution -「ARC 104E」Random LIS

    \(\mathcal{Description}\)   Link.   给定整数序列 \(\{a_n\}\),对于整数序列 \(\{b_n\}\),\(b_i\) 在 \([1,a_i]\) 中等概率 ...

  2. Solution -「CTS 2019」「洛谷 P5404」氪金手游

    \(\mathcal{Description}\)   Link.   有 \(n\) 张卡牌,第 \(i\) 张的权值 \(w_i\in\{1,2,3\}\),且取值为 \(k\) 的概率正比于 \ ...

  3. Solution -「BZOJ 3812」主旋律

    \(\mathcal{Description}\)   Link.   给定含 \(n\) 个点 \(m\) 条边的简单有向图 \(G=(V,E)\),求 \(H=(V,E'\subseteq E)\ ...

  4. Solution -「CF 1342E」Placing Rooks

    \(\mathcal{Description}\)   Link.   在一个 \(n\times n\) 的国际象棋棋盘上摆 \(n\) 个车,求满足: 所有格子都可以被攻击到. 恰好存在 \(k\ ...

  5. Solution -「Gym 102759G」LCS 8

    \(\mathcal{Description}\)   Link.   给定 \(m\),和长度为 \(n\),字符集为大写字母的字符串 \(s\),求字符集相同且等长的字符串 \(t\) 的数量,使 ...

  6. Solution -「ZJOI 2019」「洛谷 P5326」开关

    \(\mathcal{Description}\)   Link.   有 \(n\) 个开关,初始时所有开关的状态为 \(0\).给定开关的目标状态 \(s_1,s_2,\cdots,s_n\).每 ...

  7. Solution -「简单 DP」zxy 讲课记实

    魔法题位面级乱杀. 「JOISC 2020 Day4」治疗计划 因为是不太聪明的 Joker,我就从头开始理思路了.中途也会说一些和 DP 算法本身有关的杂谈,给自己的冗长题解找借口. 首先,治疗方案 ...

  8. Solution -「基环树」做题记录

    写的大多只是思路,比较简单的细节和证明过程就不放了,有需者自取. 基环树简介 简单说一说基环树吧.由名字扩展可得这是一类以环为基础的树(当然显然它不是树. 通常的表现形式是一棵树再加一条非树边,把图画 ...

  9. Solution -「WC 2022」秃子酋长

    \(\mathscr{Description}\)   Link. (It's empty temporarily.)   给定排列 \(\{a_n\}\),\(q\) 次询问,每次给出 \([l,r ...

随机推荐

  1. js- float类型相减 出现无限小数的问题

    6.3 -1.1 是不是应该等于5.2? 但是js 会导致得出 5.19999999999的结果 怎么办?可以先先乘100 后相减,然是用方法 舍入为最接近的整数,然后再除于100, Math.rou ...

  2. Echart可视化学习集合

    一.基本介绍:ECharts是一款基于JavaScript的数据可视化图表库,提供直观,生动,可交互,可个性化定制的数据可视化图表.ECharts最初由百度团队开源,并于2018年初捐赠给Apache ...

  3. fastjson字符串转JSON的$ref问题

    先说结论: fastjson在把对象转换成字符串的时候,如果遇到相同的对象的时候,默认开启引用检测将相同的对象写成引用的形式. 官网文档:https://github.com/alibaba/fast ...

  4. 《剑指offer》刷题目录

    <剑指offer>刷题目录 面试题03. 数组中重复的数字 面试题04. 二维数组中的查找 面试题05. 替换空格 面试题06. 从尾到头打印链表 面试题07. 重建二叉树 面试题09. ...

  5. 《剑指offer》面试题30. 包含min函数的栈

    问题描述 定义栈的数据结构,请在该类型中实现一个能够得到栈的最小元素的 min 函数在该栈中,调用 min.push 及 pop 的时间复杂度都是 O(1).   示例: MinStack minSt ...

  6. 浅谈 Java 多线程(一) --- JMM

    为什么使用多线程 更多的处理器核心数(硬件的发展使 CPU 趋向于更多的核心数,如果不能充分利用,就无法显著提升程序的效率) 更快的响应时间(复杂的业务场景下,会存在许多数据一致性不强的操作,如果将这 ...

  7. 【记录一个问题】cuda核函数可能存在栈溢出,导致main()函数退出后程序卡死30秒CUDA

    调试一个CUDA核函数过程中发现一个奇怪的问题:调用某个核函数,程序耗时33秒,并且主要时间是main()函数结束后的33秒:而注释掉此核函数,程序执行不到1秒. 由此可见,可能是某种栈溢出,导致了程 ...

  8. C++ 基本类型的大小

    C++的基本类型: char bool (unsigned) short (int) (unsigned) int (unsigned) long (int) (unsigned) long long ...

  9. Android 12(S) 图形显示系统 - 应用建立和SurfaceFlinger的沟通桥梁(三)

    1 前言 上一篇文章中我们已经创建了一个Native示例应用,从使用者的角度了解了图形显示系统API的基本使用,从这篇文章开始我们将基于这个示例应用深入图形显示系统API的内部实现逻辑,分析运作流程. ...

  10. 返回值String是文本数据

    MyController类中: index.jsp中 修改text前: 改为text后: 还是有乱码是因为使用这个ISO-8859-1编码处理的 MyController中修改注解中属性