1 条题解
-
1
#include <bits/stdc++.h> using namespace std; const int MAXN = 100000 + 5; int n, q; vector<int> e[MAXN]; int init_color[MAXN]; // 初始颜色 int ans[MAXN]; // 最终答案 // 每个点的:父节点、深度、大小、重子节点 int fa[MAXN], dep[MAXN], siz[MAXN], hson[MAXN]; void dfs_build(int u, int fat) { hson[u] = 0; siz[u] = 1; for (int i = 0; i < e[u].size(); i++) { int v = e[u][i]; if (v == fat) continue; dep[v] = dep[u] + 1; fa[v] = u; dfs_build(v, u); siz[u] += siz[v]; if (siz[v] > siz[hson[u]]) hson[u] = v; } } // 每个点的:所在链的链顶、重边优先的 dfs 序、dfs序对应的节点编号 int tot, top[MAXN], dfn[MAXN], rnk[MAXN]; void dfs_div(int u, int fa) { dfn[u] = ++tot; rnk[tot] = u; if (hson[u]) { top[hson[u]] = top[u]; dfs_div(hson[u], u); for (int i = 0; i < e[u].size(); i++) { int v = e[u][i]; if (v == fa || v == hson[u]) continue; top[v] = v; dfs_div(v, u); } } } struct Res { // 左边颜色,右边颜色,颜色段数 int lcolor, rcolor, sum; }; struct SegTree { int sum[4 * MAXN]; // 有多少段颜色 int lazy[4 * MAXN]; // 延迟染色,0 表示没有染色 int lcolor[4 * MAXN]; // 区间左端点颜色 int rcolor[4 * MAXN]; // 区间右端点颜色 void up(int now) { sum[now] = sum[now * 2] + sum[now * 2 + 1]; lcolor[now] = lcolor[now * 2]; rcolor[now] = rcolor[now * 2 + 1]; if (rcolor[now * 2] == lcolor[now * 2 + 1]) sum[now]--; } void down(int now, int l, int r) { if (l == r || lazy[now] == 0) return; sum[now * 2] = 1; sum[now * 2 + 1] = 1; lazy[now * 2] = lazy[now]; lcolor[now * 2] = lazy[now]; rcolor[now * 2] = lazy[now]; lazy[now * 2 + 1] = lazy[now]; lcolor[now * 2 + 1] = lazy[now]; rcolor[now * 2 + 1] = lazy[now]; lazy[now] = 0; } void build(int now, int l, int r) { lazy[now] = 0; if (l == r) { sum[now] = 1; lcolor[now] = rcolor[now] = init_color[rnk[l]]; return; } int mid = (l + r) / 2; build(now * 2, l, mid); build(now * 2 + 1, mid + 1, r); up(now); } // x~y 染成 z 色 void update(int now, int l, int r, int x, int y, int z) { if (x <= l && r <= y) { sum[now] = 1; lcolor[now] = rcolor[now] = z; lazy[now] = z; return; } down(now, l, r); int mid = (l + r) / 2; if (x <= mid) update(now * 2, l, mid, x, y, z); if (y >= mid + 1) update(now * 2 + 1, mid + 1, r, x, y, z); up(now); } Res query(int now, int l, int r, int x, int y) { if (x <= l && r <= y) return (Res){lcolor[now], rcolor[now], sum[now]}; down(now, l, r); int mid = (l + r) / 2; Res res = {0, 0, 0}; Res lRes = {0, 0, 0}; Res rRes = {0, 0, 0}; if (x <= mid) { lRes = query(now * 2, l, mid, x, y); res = lRes; } if (y >= mid + 1) { rRes = query(now * 2 + 1, mid + 1, r, x, y); if (res.lcolor == 0) res.lcolor = rRes.lcolor; res.rcolor = rRes.rcolor; res.sum += rRes.sum; } // 左右都有涉及,并且中间颜色一样,段数就少一段 if (lRes.sum > 0 && rRes.sum > 0 && lRes.rcolor == rRes.lcolor) res.sum--; return res; } } st; // u~v路径上查询颜色段数 int query(int u, int v) { int res = 0; int ulast = -1; // u上一段最后的颜色 int vlast = -1; // v上一段最后的颜色 while (top[u] != top[v]) { if (dep[top[u]] < dep[top[v]]) { // v~top[v] 计入答案中 Res now = st.query(1, 1, tot, dfn[top[v]], dfn[v]); res += now.sum; if (now.rcolor == vlast) res--; vlast = now.lcolor; v = fa[top[v]]; } else { // u~top[u] 计入答案中 Res now = st.query(1, 1, tot, dfn[top[u]], dfn[u]); res += now.sum; if (now.rcolor == ulast) res--; ulast = now.lcolor; u = fa[top[u]]; } } if (dep[u] > dep[v]) { swap(u, v); swap(ulast, vlast); } Res now = st.query(1, 1, tot, dfn[u], dfn[v]); res += now.sum; if (now.lcolor == ulast) res--; if (now.rcolor == vlast) res--; return max(res, 1); } void update(int u, int v, int z) { while (top[u] != top[v]) { if (dep[top[u]] < dep[top[v]]) { // v~top[v] 计入答案中 st.update(1, 1, tot, dfn[top[v]], dfn[v], z); v = fa[top[v]]; } else { // u~top[u] 计入答案中 st.update(1, 1, tot, dfn[top[u]], dfn[u],z); u = fa[top[u]]; } } if (dep[u] > dep[v]) swap(u, v); st.update(1, 1, tot, dfn[u], dfn[v],z); } int main() { ios::sync_with_stdio(false); cin.tie(0); cin >> n >> q; for (int i = 1; i <= n; i++) cin >> init_color[i]; for (int i = 1; i <= n - 1; i++) { int u, v; cin >> u >> v; e[u].push_back(v); e[v].push_back(u); } dep[1] = 1; fa[1] = 0; dfs_build(1, 0); tot = 0; top[1] = 1; dfs_div(1, 0); /* for(int i=1;i<=tot;i++) cout<<dfn[i]<<" "; cout<<endl; */ //-------- st.build(1, 1, tot); while (q--) { char op; int a, b, c; cin >> op; if (op == 'C') { cin >> a >> b >> c; update(a, b, c); } else if (op == 'Q') { cin >> a >> b; cout << query(a, b) << "\n"; } } return 0; }
- 1
信息
- ID
- 793
- 时间
- 1000ms
- 内存
- 512MiB
- 难度
- 7
- 标签
- 递交数
- 37
- 已通过
- 10
- 上传者