不妨採取重鏈剖分的方式把路徑剖成區間,然後用線段樹維護,考慮如何合併乙個區間
struct node seg[n << 2]; int col[n << 2];
inline node merge(const node &lc, const node &rc) ;
if(lc.rg == rc.lf) --ret.tot;
return ret;
}
其中$node$表示線段樹中的乙個節點,共有三個引數,左端點顏色,右端點顏色以及區間內顏色段數。$col$陣列用於下方染色標記。
但是我們要考慮這個區間合併後是否存在相同的顏色其應該只有$1$的貢獻卻被記了$2$的貢獻。這種情況存在當且僅當左區間的右端點顏色與右區間左端點顏色相同。
接著,有關於線段樹的其他操作也沒有什麼好擔心的了,接著考慮如何查詢。
inline int doit(int x, int y) , disy = (node);
while(fx != fy) if(dfn[x] > dfn[y]) swap(x, y), swap(disx, disy);
swap(disx.lf, disx.rg);
node ret = merge(merge(disx, query(dfn[x], dfn[y])), disy);
return ret.tot;
}
由於重鏈剖分跳$top$時,兩個端點的路徑是獨立的,所以不能像普通查詢那樣直接累加貢獻,要分開處理,最後存在乙個特殊情況,要將左區間的左右端點反置。(畫圖即可明白)
#include #include using std::swap;
typedef long long ll;
const int n = 1e5 + 10;
int n, m, c[n], w[n];
int fa[n], son[n], siz[n], dep[n];
int time, dfn[n], top[n];
int cnt, from[n], to[n << 1], nxt[n << 1];
struct node seg[n << 2]; int col[n << 2];
void addedge(int u, int v)
void dfs(int u)
}void dfs(int u, int t)
}inline node merge(const node &lc, const node &rc) ;
if(lc.rg == rc.lf) --ret.tot;
return ret;
}inline void pushdown(int o, int lc, int rc) ;
seg[rc] = (node);
col[lc] = col[rc] = col[o], col[o] = 0;
}}void build(int o = 1, int l = 1, int r = n) ; return ; }
int mid = (l + r) >> 1, lc = o << 1, rc = lc | 1;
build(lc, l, mid), build(rc, mid + 1, r), seg[o] = merge(seg[lc], seg[rc]);
}void color(int cl, int cr, int k, int o = 1, int l = 1, int r = n) , col[o] = k;
return ;
}int mid = (l + r) >> 1, lc = o << 1, rc = lc | 1;
pushdown(o, lc, rc);
if(cl <= mid) color(cl, cr, k, lc, l, mid);
if(cr > mid) color(cl, cr, k, rc, mid + 1, r);
seg[o] = merge(seg[lc], seg[rc]);
}node query(int ql, int qr, int o = 1, int l = 1, int r = n) ;
pushdown(o, lc, rc);
if(ql <= mid) ret = query(ql, qr, lc, l, mid);
if(qr > mid) ret = merge(ret, query(ql, qr, rc, mid + 1, r));
return ret;
}inline void upt(int x, int y, int k) if(dfn[x] > dfn[y]) swap(x, y);
color(dfn[x], dfn[y], k);
}inline int doit(int x, int y) , disy = (node);
while(fx != fy) if(dfn[x] > dfn[y]) swap(x, y), swap(disx, disy);
swap(disx.lf, disx.rg);
node ret = merge(merge(disx, query(dfn[x], dfn[y])), disy);
return ret.tot;
}int main ()
dfs(1), dfs(1, 1), build();
char opt; int a, b, c;
while(m--) else printf("%d\n", doit(a, b));
}return 0;
}
Luogu P2486染色(樹鏈剖分)
題目鏈結 線段樹維護左端顏色,右端顏色,顏色段數量。合併的時候看左子樹的右端顏色是不是等於右子樹的左端顏色,如果等於那麼顏色段數量要 1s 然後在樹剖跳鏈的時候搞同樣的操作qwq 然後就沒有然後了 include include include include include define maxn...
染色 樹鏈剖分
先樹剖,然後再線段樹維護 考慮對每個節點維護 n um numnu m值 表示當前區間顏色段數量 l clc lc值 表示當前區間最左端的顏色 r crc rc值 表示當前區間最右端的顏色 合併時,如果左兒子的rc rc rc 右兒子的lclc lc,那麼合併後父節點的num numnu m值還要減...
可愛的樹鏈剖分(染色)
這道題 就是 一道 普通的 樹鏈剖分 線段樹覆蓋 注意一下兩個線段樹合併的時候 如果 lva l no de 1 1 rval nod e 1 lval node 1 1 rval node 1 lval n ode 1 1 rval nod e 1 相當於這兩個線段樹的相鄰的數字數相同的 那麼合併...