【学习笔记】树链剖分系列三——边权转点权
好像我还能更。
前传1:【学习笔记】树链剖分系列1——树链剖分(重链剖分)——我是不是应该写一篇树链剖分呢
前传2:【学习笔记】树链剖分系列二——LCA
我又来回收伏笔辣:
其实跟下一篇还有点联系来着。
以及:
点权转边权
P4315 月下“毛景树”
P4114 Qtree1
P3038 [USACO11DEC]Grass Planting G
其实啊,边权转点权没啥好讲的,但我为了水博客,单开了一篇。
之前我们做的树剖是维护点权,当有题要我们维护边权时,该怎么办呢?
既然写这个,那肯定是要把边权转化成点权,再维护,需要考虑的是转化到什么点上,怎么转化。
考虑树的性质,每个点有且仅有一个父亲,所以,一个点与其父亲之间的边的权值,可以转化成这个点的权值,之后就可以像往常一样维护了。
所以,\(dfs\) 函数改一下
void dfs_deep(int rt, int father, int depth){ size[rt] = 1; fa[rt] = father; deep[rt] = depth; int max_son = -1; for(register int i = head[rt]; i; i = e[i].next){ int v = e[i].to; if(v == father) continue; dis[v] = e[i].dis; //转化成点权 dfs_deep(v, rt, depth + 1); size[rt] += size[v]; if(max_son < size[v]){ son[rt] = v; max_son = size[v]; } } }
但是仍然有需要注意的。
记得我们上一篇讲LCA的时候,说到了最后跳到的 \(x\) 点是 \(x\),\(y\) 的LCA。(伏笔回收)
LCA是在 \(x\),\(y\) 的路径上深度最小的点,然而在边权转化成点权后,LCA保存的权值是它与它父亲相连的边的权值,不在 \(x\),\(y\) 的路径上。
所以在查询/修改的时候,最后的区间是 \([dfn[x] + 1, dfn[y]]\)。
以及,要判断 \(y\) 是不是LCA,即 \(x\) 是否等于 \(y\),若相等,则无需再查询/修改了,不然会造成RE
。
查询/修改函数:
void Update_Tree(int x, int y, int data){ while(top[x] != top[y]){ if(deep[top[x]] < deep[top[y]]) swap(x, y); S.Update(1, dfn[top[x]], dfn[x], data); x = fa[top[x]]; } if(deep[x] > deep[y]) swap(x, y); if(x != y) S.Update(1, dfn[x] + 1, dfn[y], data); } int Query_Max_Tree(int x, int y){ int ans = 0; while(top[x] != top[y]){ if(deep[top[x]] < deep[top[y]]) swap(x, y); ans = max(ans, S.Query_Max(1, dfn[top[x]], dfn[x])); x = fa[top[x]]; } if(deep[x] > deep[y]) swap(x, y); if(x != y) ans = max(ans, S.Query_Max(1, dfn[x] + 1, dfn[y])); return ans; }
最后,看题:
P4315 月下“毛景树”
裸的边权转点权。
注意些细节:
下方懒标记时要先下放覆盖标记,并且加标记要清零。
对区间覆盖时加标记也要清零。
Code
#include<cstdio> #include<algorithm> using namespace std; const int MAXN = 1e5 + 10; const int INF = 2147483647; int n, cnt, num; int head[MAXN], from[MAXN], to[MAXN]; int dis[MAXN], val[MAXN]; int fa[MAXN], son[MAXN], size[MAXN], deep[MAXN]; int top[MAXN], dfn[MAXN]; struct Edge{ int to, next, dis; }e[MAXN << 1]; inline void Add(int u, int v, int w){ e[++cnt].to = v; e[cnt].dis = w; e[cnt].next = head[u]; head[u] = cnt; } void dfs_deep(int rt, int father, int depth){ size[rt] = 1; fa[rt] = father; deep[rt] = depth; int max_son = -1; for(register int i = head[rt]; i; i = e[i].next){ int v = e[i].to; if(v == father) continue; dis[v] = e[i].dis; dfs_deep(v, rt, depth + 1); size[rt] += size[v]; if(max_son < size[v]){ son[rt] = v; max_son = size[v]; } } } void dfs_top(int rt, int top_fa){ dfn[rt] = ++num; top[rt] = top_fa; val[num] = dis[rt]; if(!son[rt]) return; dfs_top(son[rt], top_fa); for(register int i = head[rt]; i; i = e[i].next){ int v = e[i].to; if(!dfn[v]) dfs_top(v, v); } } struct Segment_Tree{ struct Tree{ int l, r; int max; int lazy_cover, lazy_add; Tree(){ l = r = 0; max = 0; lazy_add = 0; lazy_cover = -1; } }tr[MAXN << 2]; inline int lson(int rt){ return rt << 1; } inline int rson(int rt){ return rt << 1 | 1; } inline void Pushup(int rt){ tr[rt].max = max(tr[lson(rt)].max, tr[rson(rt)].max); } inline void Pushdown(int rt){ if(tr[rt].lazy_cover != -1){ tr[lson(rt)].lazy_cover = tr[rt].lazy_cover; tr[rson(rt)].lazy_cover = tr[rt].lazy_cover; tr[lson(rt)].max = tr[rt].lazy_cover; tr[rson(rt)].max = tr[rt].lazy_cover; tr[lson(rt)].lazy_add = 0; tr[rson(rt)].lazy_add = 0; tr[rt].lazy_cover = -1; } if(tr[rt].lazy_add){ tr[lson(rt)].lazy_add += tr[rt].lazy_add; tr[rson(rt)].lazy_add += tr[rt].lazy_add; tr[lson(rt)].max += tr[rt].lazy_add; tr[rson(rt)].max += tr[rt].lazy_add; tr[rt].lazy_add = 0; } } void Build(int rt, int l, int r){ tr[rt].l = l; tr[rt].r = r; if(l == r){ tr[rt].max = val[l]; return; } int mid = (l + r) >> 1; Build(lson(rt), l, mid); Build(rson(rt), mid + 1, r); Pushup(rt); } void Update(int rt, int pos, int data){ if(tr[rt].l == tr[rt].r){ tr[rt].max = data; return; } Pushdown(rt); int mid = (tr[rt].l + tr[rt].r) >> 1; if(pos <= mid) Update(lson(rt), pos, data); else Update(rson(rt), pos, data); Pushup(rt); } void Change(int rt, int l, int r, int data){ if(tr[rt].l >= l && tr[rt].r <= r){ tr[rt].max += data; tr[rt].lazy_add += data; return; } Pushdown(rt); int mid = (tr[rt].l + tr[rt].r) >> 1; if(l <= mid) Change(lson(rt), l, r, data); if(r > mid) Change(rson(rt), l, r, data); Pushup(rt); } void Cover(int rt, int l, int r, int data){ if(tr[rt].l >= l && tr[rt].r <= r){ tr[rt].max = data; tr[rt].lazy_cover = data; tr[rt].lazy_add = 0; return; } Pushdown(rt); int mid = (tr[rt].l + tr[rt].r) >> 1; if(l <= mid) Cover(lson(rt), l, r, data); if(r > mid) Cover(rson(rt), l, r, data); Pushup(rt); } int Query_Max(int rt, int l, int r){ if(tr[rt].l >= l && tr[rt].r <= r) return tr[rt].max; Pushdown(rt); int ans = 0; int mid = (tr[rt].l + tr[rt].r) >> 1; if(l <= mid) ans = max(ans, Query_Max(lson(rt), l, r)); if(r > mid) ans = max(ans, Query_Max(rson(rt), l, r)); Pushup(rt); return ans; } }S; void Change_Tree(int x, int y, int data){ while(top[x] != top[y]){ if(deep[top[x]] < deep[top[y]]) swap(x, y); S.Change(1, dfn[top[x]], dfn[x], data); x = fa[top[x]]; } if(deep[x] > deep[y]) swap(x, y); if(x != y) S.Change(1, dfn[x] + 1, dfn[y], data); } void Cover_Tree(int x, int y, int data){ while(top[x] != top[y]){ if(deep[top[x]] < deep[top[y]]) swap(x, y); S.Cover(1, dfn[top[x]], dfn[x], data); x = fa[top[x]]; } if(deep[x] > deep[y]) swap(x, y); if(x != y) S.Cover(1, dfn[x] + 1, dfn[y], data); } int Query_Max_Tree(int x, int y){ int ans = 0; while(top[x] != top[y]){ if(deep[top[x]] < deep[top[y]]) swap(x, y); ans = max(ans, S.Query_Max(1, dfn[top[x]], dfn[x])); x = fa[top[x]]; } if(deep[x] > deep[y]) swap(x, y); if(x != y) ans = max(ans, S.Query_Max(1, dfn[x] + 1, dfn[y])); return ans; } inline int read(){ int x = 0, f = 1; char c = getchar(); while(c < '0' || c > '9'){ if(c == '-') f = -1; c = getchar(); } while(c >= '0' && c <= '9'){ x = (x << 1) + (x << 3) + (c ^ 48); c = getchar(); } return x * f; } int main(){ n = read(); for(register int i = 1; i <= n - 1; i++){ int u, v, w; u = read(), v = read(), w = read(); Add(u, v, w); Add(v, u, w); from[i] = u, to[i] = v; } dfs_deep(1, 0, 1); dfs_top(1, 1); S.Build(1, 1, n); while(1){ char opt[10]; scanf("%s", opt + 1); if(opt[1] == 'S') break; else if(opt[1] == 'C' && opt[2] == 'h'){ int k, w, u, v; k = read(), w = read(); u = from[k], v = to[k]; if(deep[u] < deep[v]) swap(u, v); S.Update(1, dfn[u], w); } else if(opt[1] == 'C' && opt[2] == 'o'){ int x, y, w; x = read(), y = read(), w = read(); Cover_Tree(x, y, w); } else if(opt[1] == 'A'){ int x, y, w; x = read(), y = read(), w = read(); Change_Tree(x, y, w); } else{ int x, y; x = read(), y = read(); printf("%d\n", Query_Max_Tree(x, y)); } } return 0; }
以下为博客签名,与博文无关。
只要你们不停下来,那前面就一定有我。所以啊,不要停下来~
本文来自博客园,作者:TSTYFST,转载请注明原文链接:https://www.cnblogs.com/TSTYFST/p/16596989.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)