BZOJ 2243「染色」是樹鏈剖分的經典應用:支持路徑區間染色、查詢路徑上顏色段數。本文詳細解析線段樹節點信息設計、push_up 合併邏輯、鏈上查詢時跨鏈顏色段去重的關鍵技巧。
C u v c:將 u-v 路徑上所有節點染成顏色 c。Q u v:查詢 u-v 路徑上顏色段數(連續相同顏色算一段)。pos[u] 為 u 在線段樹中的位置,同一重鏈節點位置連續,且越靠近根 pos 越小。struct Node {
int l, r; // 區間範圍
int lc, rc; // 左端點顏色、右端點顏色
int num; // 區間內顏色段數
int tag; // 懶標記:-1 表示無,≥0 表示整段染為該顏色
} seg[MAXN * 4];
void push_up(int rt) {
seg[rt].lc = seg[ls].lc;
seg[rt].rc = seg[rs].rc;
seg[rt].num = seg[ls].num + seg[rs].num;
if (seg[ls].rc == seg[rs].lc) seg[rt].num--; // 跨中點同色,段數-1
}
void push_down(int rt) {
if (seg[rt].tag != -1) {
int c = seg[rt].tag;
seg[ls].tag = seg[rs].tag = c;
seg[ls].lc = seg[ls].rc = seg[rs].lc = seg[rs].rc = c;
seg[ls].num = seg[rs].num = 1;
seg[rt].tag = -1;
}
}
u-v 路徑分解為若干重鏈區間,從 u、v 向上跳至 LCA。區間查詢返回 num、lc、rc。跨區間合併時需判斷相鄰區間的端點顏色是否相同。
[pos[top[u]], pos[u]],右端點顏色 rc 與上一條鏈的 左端點顏色 比較。[pos[v], pos[u]](假設 u 深),兩端分別與 u 方向、v 方向的記錄顏色比較。struct QueryResult {
int num, lc, rc;
};
QueryResult query(int rt, int L, int R, int ql, int qr) {
if (L == ql && R == qr) return {seg[rt].num, seg[rt].lc, seg[rt].rc};
push_down(rt);
int mid = (L + R) >> 1;
if (qr <= mid) return query(ls, L, mid, ql, qr);
if (ql > mid) return query(rs, mid+1, R, ql, qr);
auto left = query(ls, L, mid, ql, mid);
auto right = query(rs, mid+1, R, mid+1, qr);
QueryResult res;
res.num = left.num + right.num - (left.rc == right.lc);
res.lc = left.lc;
res.rc = right.rc;
return res;
}
int queryPath(int u, int v) {
int ans = 0;
int lastColorU = -1, lastColorV = -1; // 記錄上一條鏈的端點顏色
while (top[u] != top[v]) {
if (dep[top[u]] < dep[top[v]]) {
swap(u, v);
swap(lastColorU, lastColorV);
}
// u 所在鏈較深
auto res = query(1, 1, n, pos[top[u]], pos[u]);
ans += res.num;
if (res.rc == lastColorU) ans--; // 與上一條鏈左端點同色
lastColorU = res.lc;
u = fa[top[u]];
}
// 同一重鏈
if (dep[u] < dep[v]) swap(u, v), swap(lastColorU, lastColorV);
auto res = query(1, 1, n, pos[v], pos[u]);
ans += res.num;
if (res.rc == lastColorU) ans--;
if (res.lc == lastColorV) ans--;
return ans;
}
同樣分解路徑,對每個重鏈區間調用線段樹區間賦值更新(懶標記)。
本題展示了樹鏈剖分處理「路徑屬性查詢」的標準框架。核心難點在於跨鏈合併時的顏色段去重,解決方案是:
此模板可直接推廣至「路徑上不同值計數」、「路徑上最大連續同色長度」等問題。