\(\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。(大雾

#include <cstdio>

# ifdef LOCAL_DEBUG
const int MAXN = 5;
# else
const int MAXN = 1e5;
# endif
const int NINF = -( 1ll << 30 );
int n, m, ecnt, a[MAXN + 5], head[MAXN + 5];
int fa[MAXN + 5], dep[MAXN + 5], siz[MAXN + 5], son[MAXN + 5];
int dfc, dfn[MAXN + 5], ref[MAXN + 5], top[MAXN + 5]; inline int max_ ( const int a, const int b ) { return a > b ? a : b; } inline char fgc () {
static char buf[1 << 17], *p = buf, *q = buf;
return p == q && ( q = buf + fread ( p = buf, 1, 1 << 17, stdin ), p == q ) ? EOF : *p ++;
} inline int rint () {
# ifdef LOCAL_DEBUG
# define fgc getchar
# endif
int x = 0, f = 1; char s = fgc ();
for ( ; s < '0' || '9' < s; s = fgc () ) f = s == '-' ? -f : f;
for ( ; '0' <= s && s <= '9'; s = fgc () ) x = x * 10 + ( s ^ '0' );
return x * f;
} inline void wint ( int x ) {
if ( x < 0 ) putchar ( '-' ), x = -x;
if ( 9 < x ) wint ( x / 10 );
putchar ( x % 10 ^ '0' );
} struct Edge { int to, nxt; } graph[MAXN * 2 + 5]; inline void link ( const int s, const int t ) {
graph[++ ecnt] = { t, head[s] };
head[s] = ecnt;
} struct Matrix {
int mat[3][3];
Matrix (): mat { NINF, NINF, NINF, NINF, NINF, NINF, NINF, NINF, NINF } {}
inline int* operator [] ( const int key ) { return mat[key]; }
inline Matrix operator * ( Matrix t ) {
Matrix ret;
for ( int i = 0; i < 3; ++ i ) {
for ( int k = 0; k < 3; ++ k ) {
for ( int j = 0; j < 3; ++ j ) {
ret[i][j] = max_ ( ret[i][j], mat[i][k] + t[k][j] );
}
}
}
return ret;
}
}; inline Matrix identity () {
static Matrix I;
I[0][0] = I[1][1] = I[2][2] = 0;
return I;
} inline Matrix make ( const int v ) {
Matrix A;
A[0][0] = A[0][2] = A[1][2] = A[2][2] = 0;
A[0][1] = A[1][1] = v;
return A;
} inline Matrix power ( const int v, const int k ) {
Matrix A;
A[0][0] = A[2][2] = 0;
A[0][1] = max_ ( v, k * v );
A[0][2] = A[1][2] = max_ ( 0, k * v );
A[1][1] = k * v;
return A;
} struct SegmentTree {
Matrix S[2][MAXN * 2 + 5]; int tag[MAXN * 2 + 5];
inline int id ( const int l, const int r ) { return ( l + r ) | ( l != r ); }
inline void pushup ( const int l, const int r ) {
int rt = id ( l, r ), mid = l + r >> 1, lc = id ( l, mid ), rc = id ( mid + 1, r );
S[0][rt] = S[0][lc] * S[0][rc], S[1][rt] = S[1][rc] * S[1][lc];
}
inline void pushas ( const int l, const int r, const int v ) {
int rt = id ( l, r );
S[0][rt] = S[1][rt] = power ( v, r - l + 1 ), tag[rt] = v;
}
inline void pushdn ( const int l, const int r ) {
int rt = id ( l, r ), mid = l + r >> 1;
if ( tag[rt] == NINF ) return ;
pushas ( l, mid, tag[rt] ), pushas ( mid + 1, r, tag[rt] );
tag[rt] = NINF;
}
inline void build ( const int l, const int r ) {
int rt = id ( l, r ), mid = l + r >> 1;
tag[rt] = NINF;
if ( l == r ) return void ( S[0][rt] = S[1][rt] = make ( a[ref[l]] ) );
build ( l, mid ), build ( mid + 1, r );
pushup ( l, r );
}
inline void assign ( const int l, const int r, const int al, const int ar, const int v ) {
int mid = l + r >> 1;
if ( al <= l && r <= ar ) return pushas ( l, r, v );
pushdn ( l, r );
if ( al <= mid ) assign ( l, mid, al, ar, v );
if ( mid < ar ) assign ( mid + 1, r, al, ar, v );
pushup ( l, r );
}
inline Matrix query ( const int l, const int r, const int ql, const int qr, const bool type ) {
int rt = id ( l, r ), mid = l + r >> 1;
if ( ql <= l && r <= qr ) return S[type][rt];
pushdn ( l, r );
if ( qr <= mid ) return query ( l, mid, ql, qr, type );
else if ( mid < ql ) return query ( mid + 1, r, ql, qr, type );
else return ! type ?
query ( l, mid, ql, qr, 0 ) * query ( mid + 1, r, ql, qr, 0 ):
query ( mid + 1, r, ql, qr, 1 ) * query ( l, mid, ql, qr, 1 );
}
} st; inline void DFS1 ( const int u, const int f ) {
dep[u] = dep[fa[u] = f] + ( siz[u] = 1 );
for ( int i = head[u], v; i; i = graph[i].nxt ) {
if ( ( v = graph[i].to ) ^ f ) {
DFS1 ( v, u ), siz[u] += siz[v];
if ( siz[son[u]] < siz[v] ) son[u] = v;
}
}
} inline void DFS2 ( const int u, const int tp ) {
ref[dfn[u] = ++ dfc] = u, top[u] = tp;
if ( son[u] ) DFS2 ( son[u], tp );
for ( int i = head[u], v; i; i = graph[i].nxt ) {
if ( ( v = graph[i].to ) ^ fa[u] && v ^ son[u] ) {
DFS2 ( v, v );
}
}
} inline void assignChain ( int u, int v, const int w ) {
while ( top[u] ^ top[v] ) {
if ( dep[top[u]] < dep[top[v]] ) u ^= v ^= u ^= v;
st.assign ( 1, n, dfn[top[u]], dfn[u], w );
u = fa[top[u]];
}
if ( dep[u] < dep[v] ) u ^= v ^= u ^= v;
st.assign ( 1, n, dfn[v], dfn[u], w );
} inline int queryChain ( int u, int v ) {
Matrix A ( identity () ), B ( identity () );
while ( top[u] ^ top[v] ) {
if ( dep[top[u]] < dep[top[v]] ) {
B = st.query ( 1, n, dfn[top[v]], dfn[v], 0 ) * B;
v = fa[top[v]];
} else {
A = A * st.query ( 1, n, dfn[top[u]], dfn[u], 1 );
u = fa[top[u]];
}
}
if ( dep[u] > dep[v] ) A = A * st.query ( 1, n, dfn[v], dfn[u], 1 );
else B = st.query ( 1, n, dfn[u], dfn[v], 0 ) * B;
A = A * B;
return max_ ( A[0][1], A[0][2] );
} int main () {
n = rint ();
for ( int i = 1; i <= n; ++ i ) a[i] = rint ();
for ( int i = 1, u, v; i < n; ++ i ) {
u = rint (), v = rint ();
link ( u, v ), link ( v, u );
}
DFS1 ( 1, 0 ), DFS2 ( 1, 1 );
st.build ( 1, n );
for ( int q = rint (), op, a, b, c; q --; ) {
op = rint (), a = rint (), b = rint ();
if ( op & 1 ) {
wint ( queryChain ( a, b ) );
putchar ( '\n' );
} else {
c = rint ();
assignChain ( a, b, c );
}
}
return 0;
}

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. spring-data-jpa -hibernate --specificationExecutor

    Specifications动态查询 在查询某个实体的时候,给定的条件是不固定的,这时就需要动态构建相应的查询语句,在Spring Data JPA中可以通过JpaSpecificationExecu ...

  2. 读《疯狂Java讲义》笔记总结一

    最近在读<疯狂Java讲义>,现把其中遇到的一些自己以前没掌握的点儿记录下来. 1.字符串相关 字符串不是基本类型,字符串是一个类,也就是一个引用类型. 字符串转int类型String a ...

  3. Go - 如何编写 ProtoBuf 插件 (三) ?

    目录 前言 演示代码 小结 推荐阅读 前言 上篇文章<Go - 如何编写 ProtoBuf 插件 (二) >,分享了基于 自定义选项 定义了 interceptor 插件,然后在 hell ...

  4. Solon 开发,五、切面与环绕拦截

    Solon 开发 一.注入或手动获取配置 二.注入或手动获取Bean 三.构建一个Bean的三种方式 四.Bean 扫描的三种方式 五.切面与环绕拦截 六.提取Bean的函数进行定制开发 七.自定义注 ...

  5. golang中数组指针与指针数组的区别实现

      指针数组和数组的指针,指的是两个不同的东西. 指针数组是有指针组成的数组,数组的指针是一个数组的指针. package main import "fmt" const MAX ...

  6. ajax返回获取的值在其他地方获取

    继续上个问题的后续问题,因为要获取token进行身份验证,但是又不想写死token值,通过以下方式解决: 1.定义一个分离出来的方法. 2.定义一个全局变量.局部变量. 3.把ajax改成同步的.as ...

  7. 科技爱好者周刊(第 176 期):中国法院承认 GPL 吗?

    这里记录每周值得分享的科技内容,周五发布. 本杂志开源(GitHub: ruanyf/weekly),欢迎提交 issue,投稿或推荐科技内容. 周刊讨论区的帖子<谁在招人?>,提供大量程 ...

  8. APC 篇——备用 APC 队列

    写在前面   此系列是本人一个字一个字码出来的,包括示例和实验截图.由于系统内核的复杂性,故可能有错误或者不全面的地方,如有错误,欢迎批评指正,本教程将会长期更新. 如有好的建议,欢迎反馈.码字不易, ...

  9. linux搭建本地和网络yum源

    [mirrors.163.com] name=mirrors.163.com baseurl=http://mirrors.163.com/centos/7/os/x86_64/ enabled=1 ...

  10. 从我做起[AutoMapper实现模块化注册自定义扩展MapTo<>()].Net Core 之二

    AutoMapper实现模块化注册自定义扩展MapTo<>() 我们都知道AutoMapper是使用的最多的实体模型映射,如果没有AutoMapper做对象映射那么我们需要想一下是怎么写的 ...