loj10141. 「一本通 4.5 练习 3」染色
Posted junk-yao-blog
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了loj10141. 「一本通 4.5 练习 3」染色相关的知识,希望对你有一定的参考价值。
思路:
利用树链剖分转化为线段树问题,考虑线段上经这两种操作后的sum求值方法,并着重考虑树链合并的情况即可。线段树为了打cov,要注意将所有的颜色统一加一。
#include<cstdio> #include<iostream> using namespace std; const int maxn = 100010; inline void qread(int &x){ x = 0; register int ch = getchar(); while(ch < ‘0‘ || ch > ‘9‘) ch = getchar(); while(ch >= ‘0‘ && ch <= ‘9‘) x = 10 * x + ch - 48, ch = getchar(); } int n, q; int head[maxn]; int go[maxn << 1]; int nxt[maxn << 1]; int val[maxn]; int size[maxn]; int son[maxn]; int deep[maxn]; int f[maxn]; int top[maxn]; int seg[maxn]; int rev[maxn]; int end[maxn]; int sum[maxn << 2]; int cov[maxn << 2]; inline void init(){ qread(n); qread(q); for(int i=1; i<=n; ++i){ qread(val[i]); ++val[i]; } for(int i=1; i<n; ++i){ int x, y; qread(x), qread(y); go[i] = y; nxt[i] = head[x]; head[x] = i; go[i + n] = x; nxt[i + n] = head[y]; head[y] = i + n; } deep[1] = top[1] = seg[0] = seg[1] = rev[1] = 1; } void dfs1(int x){ size[x] = 1; for(register int i = head[x]; i; i = nxt[i]) if(!deep[go[i]]){ f[go[i]] = x; deep[go[i]] = deep[x] + 1; dfs1(go[i]); size[x] += size[go[i]]; if(size[go[i]] > size[son[x]]) son[x] = go[i]; } } void dfs2(int x){ end[x] = x; if(son[x]){ top[son[x]] = top[x]; seg[son[x]] = ++seg[0]; rev[seg[0]] = son[x]; dfs2(son[x]); end[x] = end[son[x]]; } for(register int i = head[x]; i; i = nxt[i]) if(!top[go[i]]){ top[go[i]] = go[i]; seg[go[i]] = ++seg[0]; rev[seg[0]] = go[i]; dfs2(go[i]); end[x] = end[go[i]]; } } void build(int l, int r, int x){ if(l == r){ sum[x] = 1; return ; } int mid = (l + r) >> 1; build(l, mid, x << 1); build(mid + 1, r, x << 1 | 1); sum[x] = sum[x << 1] + sum[x << 1 | 1] - (val[rev[mid]] == val[rev[mid + 1]]); } inline void pushdown(int x){ cov[x << 1] = cov[x]; cov[x << 1 | 1] = cov[x]; sum[x << 1] = 1; sum[x << 1 | 1] = 1; cov[x] = 0; } int visit(int l, int r, int P, int x){ if(l == r) return cov[x] ? cov[x] : val[rev[l]]; if(cov[x]) pushdown(x); int mid = (l + r) >> 1; if(mid >= P) return visit(l, mid, P, x << 1); else return visit(mid + 1, r, P, x << 1 | 1); } void change(int l, int r, int L, int R, int v, int x){ if(L <= l && R >= r){ cov[x] = v; sum[x] = 1; return ; } if(cov[x]) pushdown(x); int mid = (l + r) >> 1; if(mid >= L) change(l, mid, L, R, v, x << 1); if(mid < R) change(mid + 1, r, L, R, v, x << 1 | 1); sum[x] = sum[x << 1] + sum[x << 1 | 1] - (visit(1, n, mid, 1) == visit(1, n, mid + 1, 1)); } int ask(int l, int r, int L, int R, int x){ if(L <= l && R >= r) return sum[x]; if(cov[x]) pushdown(x); int mid = (l + r) >> 1, cnt = 0, ans = 0; if(mid >= L) ++cnt, ans += ask(l, mid, L, R, x << 1); if(mid < R) ++cnt, ans += ask(mid + 1, r, L, R, x << 1 | 1); if(cnt == 2) ans -= (visit(1, n, mid, 1) == visit(1, n, mid + 1, 1)); return ans; } int treeask(int x, int y){ int fx = top[x], fy = top[y], ans = 0; while(fx != fy){ if(deep[fx] < deep[fy]) swap(x, y), swap(fx, fy); ans += ask(1, n, seg[fx], seg[x], 1); if(f[fx] != 0 && visit(1, n, seg[fx], 1) == visit(1, n, seg[f[fx]], 1)) ans--; x = f[fx]; fx = top[x]; } if(deep[x] > deep[y]) swap(x, y); ans += ask(1, n, seg[x], seg[y], 1); return ans; } void treechange(int x, int y, int z){ int fx = top[x], fy = top[y]; while(fx != fy){ if(deep[fx] < deep[fy]) swap(x, y), swap(fx, fy); change(1, n, seg[fx], seg[x], z, 1); x = f[fx]; fx = top[x]; } if(deep[x] > deep[y]) swap(x, y); change(1, n, seg[x], seg[y], z, 1); } int main(void) { init(); dfs1(1); dfs2(1); build(1, n, 1); while(q--){ string op; cin >> op; if(op == "C") { int a, b, c; qread(a), qread(b), qread(c); ++c; treechange(a, b, c); } else{ int a, b; qread(a), qread(b); printf("%d ", treeask(a, b)); } } }
以上是关于loj10141. 「一本通 4.5 练习 3」染色的主要内容,如果未能解决你的问题,请参考以下文章
SPFA算法的SLF优化 ——loj#10081. 「一本通 3.2 练习 7」道路和航线