【学习笔记】树链剖分系列三——边权转点权
好像我还能更。
前传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