2 条题解
-
0
难点在如何用线段树实现染色。
(以下讲述,端点是 dfs 树上的点,节点的线段树上的点)
线段树结构体里面多定义 l_col 和 r_col,分别代表管辖范围左右端点的颜色。
再定义个 cnt 表示当前节点管辖范围的颜色段数量。
更新的时候比较左节点的 r_col 和右节点 l_col,如果一样 tr[p].cnt = 左右节点 cnt 和 - 1。
不然就 tr[p].cnt = 左右节点 cnt。
你以为这样就完了?
发挥惊人的注意力,发现 get_sum 函数没那么简单,要返回一个结构体。
node get_node(int p, int l, int r) { if (tr[p].r < l || tr[p].l > r) { return (node){0, 0, -1, -1, 0, -1}; } if (l <= tr[p].l && tr[p].r <= r) { return tr[p]; } pushdown(p); node res; node a = get_node(lc(p), l, r); node b = get_node(rc(p), l, r); res = merge(a, b); return res; }我们考虑构造一个函数 merge,负责合并两个节点,和 pushup 差不多。
node merge(node a, node b) { node res; if (a.cnt == 0) { return b; } if (b.cnt == 0) { return a; } res.l_col = a.l_col; res.r_col = b.r_col; res.cnt = a.cnt + b.cnt; if (a.r_col == b.l_col) { res.cnt --; } return res; }同时 pushup 函数也应该保留,防止混乱。
再来看询问路径函数:
int query_path(int x, int y) { node t_x = {0, 0, -1, -1, 0, -1}; node t_y = {0, 0, -1, -1, 0, -1}; while (top[x] != top[y]) { if (dep[top[x]] > dep[top[y]]) { node no = get_node(1, dfn[top[x]], dfn[x]); t_x = merge(no, t_x); x = fa[top[x]]; } else { node no = get_node(1, dfn[top[y]], dfn[y]); t_y = merge(no, t_y); y = fa[top[y]]; } } if (dep[x] > dep[y]) { swap(x, y); swap(t_x, t_y); } node no = get_node(1, dfn[x], dfn[y]); node res = merge(no, t_y); swap(t_x.l_col, t_x.r_col); res = merge(t_x, res); return res.cnt; }我们需要建两个结构体分别记录 x 和 y 的重链,防止混淆。
最后合并时优先把同端点的合并。
我们设一开始的 x y 就是 x y,while 之后的 x y 是 tx 和 ty。
那么 t_x 就是 tx -> x 的链, t_y 就是 ty -> y 的链。
(因为默认求重链就是 dfn 小的 -> dfn 大的)
no 就是 tx - > ty 的链。
那么我们先把 no 和 y 连起来变成 tx - > y,
再把 t_x 的前后翻转,变成 x -> tx。
最后 t_x 和 no 合并,x -> tx -> ty -> y。
最后注意颜色初始化要等于 -1,懒标记只有不等于 -1 的时候才 pushup,
pushup 和 pushdown 不要忘写了或者写多了,这道题应该就没问题。
完整代码:
#include<bits/stdc++.h> using namespace std; typedef long long LL; const int N = 1e5 + 10; int num[N]; vector<int> G[N]; int fa[N], siz[N], son[N], dep[N]; void fir_dfs(int x, int x_fa) { fa[x] = x_fa; siz[x] = 1; son[x] = -1; dep[x] = dep[x_fa] + 1; for (int y : G[x]) if (y != x_fa) { fir_dfs(y, x); if ( (son[x] == -1) || (siz[son[x]] < siz[y]) ) { son[x] = y; } siz[x] += siz[y]; } } int tsp, dfn[N], r_dfn[N], top[N]; void sec_dfs(int x, int tp) { tsp ++; dfn[x] = tsp; r_dfn[dfn[x]] = x; top[x] = tp; if (son[x] != -1) { sec_dfs(son[x], tp); } for (int y : G[x]) if (y != son[x] && y != fa[x]) { sec_dfs(y, y); } } #define lc(p) p << 1 #define rc(p) (p << 1) | 1 struct node { int l, r; int l_col, r_col; // 左右端点的颜色 int cnt, lazy; // 颜色段数量,懒标记 } tr[4 * N]; void pushup(int p) { tr[p].l_col = tr[lc(p)].l_col; tr[p].r_col = tr[rc(p)].r_col; tr[p].cnt = tr[lc(p)].cnt + tr[rc(p)].cnt; if (tr[lc(p)].r_col == tr[rc(p)].l_col) { tr[p].cnt --; } } void pushdown(int p) { if (tr[p].lazy != -1) { tr[lc(p)].l_col = tr[lc(p)].r_col = tr[p].lazy; tr[lc(p)].cnt = 1; tr[lc(p)].lazy = tr[p].lazy; tr[rc(p)].l_col = tr[rc(p)].r_col = tr[p].lazy; tr[rc(p)].cnt = 1; tr[rc(p)].lazy = tr[p].lazy; tr[p].lazy = -1; } } void build(int p, int l, int r) { tr[p] = {l, r, -1, -1, r - l + 1, -1}; // 有关颜色的都一开始等于 -1 if (l == r) { tr[p].l_col = tr[p].r_col = num[r_dfn[l]]; return ; } int mid = (l + r) >> 1; build(lc(p), l, mid); build(rc(p), mid + 1, r); pushup(p); } void change(int p, int l, int r, int c) { if (tr[p].r < l || tr[p].l > r) { return ; } if (l <= tr[p].l && tr[p].r <= r) { tr[p].l_col = tr[p].r_col = c; tr[p].cnt = 1; tr[p].lazy = c; return ; } pushdown(p); change(lc(p), l, r, c); change(rc(p), l, r, c); pushup(p); } node merge(node a, node b) { node res; if (a.cnt == 0) { return b; } if (b.cnt == 0) { return a; } res.l_col = a.l_col; res.r_col = b.r_col; res.cnt = a.cnt + b.cnt; if (a.r_col == b.l_col) { res.cnt --; } return res; } node get_node(int p, int l, int r) { if (tr[p].r < l || tr[p].l > r) { return (node){0, 0, -1, -1, 0, -1}; } if (l <= tr[p].l && tr[p].r <= r) { return tr[p]; } pushdown(p); node res; node a = get_node(lc(p), l, r); node b = get_node(rc(p), l, r); res = merge(a, b); return res; } void change_path(int x, int y, int c) { while (top[x] != top[y]) { if (dep[top[x]] < dep[top[y]]) { swap(x, y); } change(1, dfn[top[x]], dfn[x], c); x = fa[top[x]]; } if (dep[x] > dep[y]) { swap(x, y); } change(1, dfn[x], dfn[y], c); } int query_path(int x, int y) { node t_x = {0, 0, -1, -1, 0, -1}; node t_y = {0, 0, -1, -1, 0, -1}; while (top[x] != top[y]) { if (dep[top[x]] > dep[top[y]]) { node no = get_node(1, dfn[top[x]], dfn[x]); t_x = merge(no, t_x); x = fa[top[x]]; } else { node no = get_node(1, dfn[top[y]], dfn[y]); t_y = merge(no, t_y); y = fa[top[y]]; } } if (dep[x] > dep[y]) { swap(x, y); swap(t_x, t_y); } node no = get_node(1, dfn[x], dfn[y]); node res = merge(no, t_y); swap(t_x.l_col, t_x.r_col); res = merge(t_x, res); return res.cnt; } int main () { ios::sync_with_stdio(false); cin.tie(0); int n, m; cin >> n >> m; for (int i = 1; i <= n; i ++) { cin >> num[i]; } for (int i = 1; i < n; i ++) { int x, y; cin >> x >> y; G[x].push_back(y); G[y].push_back(x); } dep[0] = 0; fir_dfs(1, 0); tsp = 0; sec_dfs(1, 1); build(1, 1, n); for (int i = 1; i <= m; i ++) { char s[5]; cin >> s; if (s[0] == 'C') { int x, y, c; cin >> x >> y >> c; change_path(x, y, c); } else { int x, y; cin >> x >> y; cout << query_path(x, y) << "\n"; } } return 0; } -
0
#include <cstdio> #include <algorithm> using namespace std; const int N=100005, M=N<<1; struct edge{int y, pre;}a[M];int alen, last[N]; inline void ins(int x, int y){a[++alen]={y, last[x]};last[x]=alen;} int b[N]; int dep[N], f[N], son[N], siz[N], top[N], dfn[N], rk[N], id; void dfs(int x, int fa, int d){ dep[x]=d; f[x]=fa; siz[x]=1; for(int k=last[x], y; k; k=a[k].pre){ if((y=a[k].y)==fa)continue; dfs(y, x, d+1); siz[x]+=siz[y]; if(siz[y]>siz[son[x]])son[x]=y; } } void dfs2(int x, int t){ top[x]=t; dfn[x]=++id; rk[id]=x; if(!son[x])return; dfs2(son[x], t); for(int k=last[x], y; k; k=a[k].pre) if((y=a[k].y)!=son[x]&&y!=f[x]) dfs2(y, y); } struct node{ int l, r, s; friend inline node operator+(node x, node y){ if(!x.s)return y; if(!y.s)return x; return {x.l, y.r, x.s+y.s-(x.r==y.l)}; } }; struct trnode{int l, r, lc, rc; node d;}tr[M];int trlen; #define ls(x) tr[x].lc #define rs(x) tr[x].rc inline void pushup(int x){tr[x].d=tr[ls(x)].d+tr[rs(x)].d;} inline void pushdown(int x){if(tr[x].d.s==1)tr[ls(x)].d=tr[rs(x)].d=tr[x].d;} int build(int l, int r){ int now=++trlen; tr[now]={l, r, -1, -1, {0,0,0}}; if(l==r)return tr[now].d={b[rk[l]], b[rk[l]], 1}, now; int mid=(l+r)>>1; ls(now)=build(l, mid); rs(now)=build(mid+1, r); pushup(now); return now; } void change(int now, int l, int r, int c){ if(tr[now].l==l&&tr[now].r==r)return tr[now].d={c, c, 1}, void(); pushdown(now); int mid=(tr[now].l+tr[now].r)>>1; if(r<=mid)change(ls(now), l, r, c); else if(mid+1<=l)change(rs(now), l, r, c); else change(ls(now), l, mid, c), change(rs(now), mid+1, r, c); pushup(now); } node query(int now, int l, int r){ if(tr[now].l==l&&tr[now].r==r)return tr[now].d; pushdown(now); int mid=(tr[now].l+tr[now].r)>>1; if(r<=mid)return query(ls(now), l, r); if(mid+1<=l)return query(rs(now), l, r); return query(ls(now), l, mid)+query(rs(now), mid+1, r); } void change(int x, int y, int c){ while(top[x]!=top[y]){ if(dep[top[x]]<dep[top[y]])swap(x, y); change(1, dfn[top[x]], dfn[x], c); x=f[top[x]]; } if(dep[x]>dep[y])swap(x, y); change(1, dfn[x], dfn[y], c); } int query(int x, int y){ node s1={0,0,0}, s2={0,0,0}; while(top[x]!=top[y]){ if(dep[top[x]]<dep[top[y]])swap(x, y), swap(s1, s2); s1=query(1, dfn[top[x]], dfn[x])+s1; x=f[top[x]]; } if(dep[x]>dep[y])s1=query(1, dfn[y], dfn[x])+s1; else s2=query(1, dfn[x], dfn[y])+s2; swap(s1.l, s1.r); return (s1+s2).s; } char s[5]; int main(){ int n, m;scanf("%d%d", &n, &m); for(int i=1; i<=n; ++i)scanf("%d", &b[i]); for(int i=1, x, y; i<n; ++i){ scanf("%d%d", &x, &y); ins(x, y);ins(y, x); } dfs(1, 0, 1);dfs2(1, 1); build(1, n); for(int i=1, x, y, c; i<=m; ++i){ scanf("%s%d%d", s, &x, &y); if(s[0]=='C')scanf("%d", &c), change(x, y, c); else printf("%d\n", query(x, y)); } return 0; }
- 1
信息
- ID
- 3908
- 时间
- 1000ms
- 内存
- 128MiB
- 难度
- 10
- 标签
- 递交数
- 8
- 已通过
- 5
- 上传者