題解 SP6779 【GSS7 - Can you answer these queries VII】
阿新 • • 發佈:2020-07-27
題目大意
給出一個\(n\)個點的樹,每個點有權值。有\(m\)次操作,每次要麼查詢一條鏈上的最大子段和,要麼把一條鏈的權值都修改為一個常數。
\(n,m\le 10^5\)
思路
如果是一維的話,我們不難列出動態\(\texttt{dp}\)轉移式:
\[\begin{bmatrix}0&a_i&0\\-\infty&a_i&0\\-\infty&-\infty&0\end{bmatrix}\begin{bmatrix}g_{i-1}\\f_{i-1}\\0\end{bmatrix}=\begin{bmatrix}g_i\\f_i\\0\end{bmatrix} \]
不懂得話可以去看一下GSS1的題解。
這道題要求一個鏈的答案,那我們直接求出這個鏈的矩陣之積即可,用樹剖就好了,修改也很簡單。需要注意的是,矩陣乘法有沒有交換律的,所以需要維護兩種不同方向的矩陣之積。
這道題有點卡常,所以快速冪不能樸素快速冪,而是找一下規律,具體見程式碼。
\(\texttt{Code}\)
#include <bits/stdc++.h> using namespace std; #define Int register int #define INF 0x7f7f7f7f #define MAXN 100005 template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;} template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);} template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');} int n,m,wei[MAXN]; struct Matrix{ int val[3][3]; Matrix(){memset (val,0xcf,sizeof (val));} int* operator [](int x){return val[x];} Matrix operator * (const Matrix &p)const{ Matrix New; for (Int i = 0;i < 3;++ i) for (Int j = 0;j < 3;++ j) for (Int k = 0;k < 3;++ k) New[i][j] = max (New[i][j],val[i][k] + p.val[k][j]); return New; } }; Matrix init (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; } Matrix III (){ Matrix res; for (Int i = 0;i < 3;++ i) res[i][i] = 0; return res; } Matrix qkpow (int v,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 edge{ int v,nxt; }e[MAXN << 1]; int toop = 1,head[MAXN]; void Add_Edge (int u,int v){ e[++ toop] = edge {v,head[u]},head[u] = toop; e[++ toop] = edge {u,head[v]},head[v] = toop; } int Index,dep[MAXN],siz[MAXN],son[MAXN],dfn[MAXN],par[MAXN],top[MAXN],tur[MAXN]; void dfs1 (int u,int fa){ par[u] = fa,dep[u] = dep[fa] + 1,siz[u] = 1; for (Int i = head[u];i;i = e[i].nxt){ int v = e[i].v; if (v == fa) continue; dfs1 (v,u),siz[u] += siz[v]; if (siz[v] > siz[son[u]]) son[u] = v; } } void dfs2 (int u,int Top){ dfn[u] = ++ Index,tur[Index] = u,top[u] = Top; if (son[u]) dfs2 (son[u],Top); for (Int i = head[u];i;i = e[i].nxt){ int v = e[i].v; if (v == par[u] || v == son[u]) continue; dfs2 (v,v); } } struct Segment{ #define len(x) (tree[x].r-tree[x].l+1) struct node{ int l,r,tag;Matrix Sum[2]; }tree[MAXN << 2]; void Pushup (int x){ tree[x].Sum[0] = tree[x << 1].Sum[0] * tree[x << 1 | 1].Sum[0]; tree[x].Sum[1] = tree[x << 1 | 1].Sum[1] * tree[x << 1].Sum[1]; } void Pushadd (int x,int v){ tree[x].tag = v; tree[x].Sum[0] = tree[x].Sum[1] = qkpow (v,len (x)); } void Pushdown (int x){ if (tree[x].tag == INF) return ; Pushadd (x << 1,tree[x].tag),Pushadd (x << 1 | 1,tree[x].tag); tree[x].tag = INF; } void build (int i,int l,int r){ tree[i].l = l,tree[i].r = r,tree[i].tag = INF; if (l == r) return tree[i].Sum[0] = tree[i].Sum[1] = init(wei[tur[l]]),void (); int mid = (l + r) >> 1; build (i << 1,l,mid),build (i << 1 | 1,mid + 1,r); Pushup (i); } Matrix query (int i,int l,int r,int type){ if (tree[i].l >= l && tree[i].r <= r) return tree[i].Sum[type]; int mid = (tree[i].l + tree[i].r) >> 1; Pushdown (i); if (r <= mid) return query (i << 1,l,r,type); else if (l > mid) return query (i << 1 | 1,l,r,type); else return !type ? query (i << 1,l,r,type) * query (i << 1 | 1,l,r,type) : query (i << 1 | 1,l,r,type) * query (i << 1,l,r,type); } void Change (int i,int l,int r,int v){ if (tree[i].l >= l && tree[i].r <= r) return Pushadd (i,v); int mid = (tree[i].l + tree[i].r) >> 1; Pushdown (i); if (l <= mid) Change (i << 1,l,r,v); if (r > mid) Change (i << 1 | 1,l,r,v); Pushup (i); } #undef len(x) }Tree; int QueryChain (int x,int y){ Matrix A,B;A = B = III(); while (top[x] ^ top[y]){ if (dep[top[x]] > dep[top[y]]){ A = A * Tree.query (1,dfn[top[x]],dfn[x],1); x = par[top[x]]; } else{ B = Tree.query (1,dfn[top[y]],dfn[y],0) * B; y = par[top[y]]; } } if (dfn[x] < dfn[y]) B = Tree.query (1,dfn[x],dfn[y],0) * B; else A = A * Tree.query (1,dfn[y],dfn[x],1);A = A * B; return max (A[0][1],A[0][2]); } void UpdateChain (int x,int y,int v){ while (top[x] ^ top[y]){ if (dep[top[x]] < dep[top[y]]) swap (x,y); Tree.Change (1,dfn[top[x]],dfn[x],v); x = par[top[x]]; } if (dfn[x] > dfn[y]) swap (x,y); Tree.Change (1,dfn[x],dfn[y],v); } signed main(){ read (n); for (Int i = 1;i <= n;++ i) read (wei[i]); for (Int i = 2,u,v;i <= n;++ i) read (u,v),Add_Edge (u,v); dfs1 (1,0),dfs2 (1,1),Tree.build (1,1,n); read (m); while (m --){ int opt,a,b,c; read (opt,a,b); if (opt == 1) write (QueryChain (a,b)),putchar ('\n'); else read (c),UpdateChain (a,b,c); } return 0; }