P4315 月下“毛景树”(树链剖分)

题面

简述: 边权转点权(在dfs1处转换) 把一条边权赋值在深度更深的上

需要实现对单边权的染色 , 路径边权的染色 , 路径边权的增加 , 路径边权的最大值查询

边权转点权后查询路径最值, uvlca的权值是它上一条边的权值,并不属于 u-v这条路径,所以我们在退出 top[u]!= top[v]这层循环,进行最后一次操作时应将 uDFS 序加上 1 ,这样就可以忽略 lca 这个点了(记住如果循环结束后u=v要 直接return)。

有两种修改操作,所以需要两个懒标记,并且在下传标记时,要先实行染色标记,再实行增值标记(与区间乘加操作相同)。

Code
#include <bits/stdc++.h>
using namespace std;
#define re(a, b, c) for (int a = (b), LEN = (c); a <= LEN; ++a)
#define er(a, b, c) for (int a = (b), LEN = (c); a >= LEN; --a)
#define endl '\n'
using i64 = long long;
const int inf = INT_MIN;
// using i128=__int128;
template <typename T>
struct tree_chain {
int n, root;
vector<int> dfn, fa, son, dep, top, sz;
vector<T> val, old;
tree_chain(const vector<vector<pair<int, T>>> &adj, int _n, int _root) : n(_n), root(_root) {
dfn.resize(n), fa.resize(n), son.assign(n, -1), old.resize(n);
dep.resize(n), top.resize(n), sz.resize(n), val.resize(n);
dfs1(adj, root, -1, 1), dfs2(adj, root, root);
}
void dfs1(const vector<vector<pair<int, T>>> &adj, int now, int fath, int depth) {
dep[now] = depth;
fa[now] = fath;
sz[now] = 1;
int max_son = -1;
for (auto [v, c] : adj[now]) {
if (v == fath) continue;
old[v] = c;//边权转点权
dfs1(adj, v, now, depth + 1), sz[now] += sz[v]; // this position can solve edge value
if (sz[v] > max_son) son[now] = v, max_son = sz[v];
}
}
void dfs2(const vector<vector<pair<int, T>>> &adj, int now, int top_id) {
static int tot = -1;
dfn[now] = ++tot, val[tot] = old[now], top[now] = top_id;
if (son[now] == -1) return;
dfs2(adj, son[now], top_id);
for (auto [v, c] : adj[now])
if (v != fa[now] and v != son[now]) dfs2(adj, v, v);
}
int lca(int u, int v) {
while (top[u] != top[v]) dep[top[u]] >= dep[top[v]] ? u = fa[top[u]] : v = fa[top[v]];
return dep[u] < dep[v] ? u : v;
}
int dist(int u, int v) { return dep[u] + dep[v] - 2 * dep[lca(u, v)]; }
/*
while (top[x] != top[y]) {
if (dep[top[x]] < dep[top[y]]) swap(x, y);
do something...
x = fa[top[x]];
}
if (dep[x] > dep[y]) swap(x, y);
do something...
*/
}; // the idx of begin is 0 ,notice use dfn when?
class segtree {
public:
struct node {
// don't forget to set default value (used for leaves)
i64 maxx = inf;
i64 add = 0;
i64 ass = inf;
void apply(int l, int r, i64 v) {
// make v become node(tag,data) in modify
add += v;
maxx += v;
}
void init(i64 v) {
// in build_tree init
maxx = v;
add = 0;
ass = inf;
}
}; node unite(const node &a, const node &b) const {
node res;
res.maxx = max(a.maxx, b.maxx);
return res;
}
// about x: left son is x+1 , right son is x+((mid-l+1)<<1) ;
inline void push_down(int x, int l, int r) {
int y = (l + r) >> 1;
int z = x + ((y - l + 1) << 1);
// push from x into (x + 1) and z
if (tree[x].ass >= 0) {
tree[x + 1].maxx = tree[x + 1].ass = tree[x].ass;
tree[z].maxx = tree[z].ass = tree[x].ass;
tree[x + 1].add = tree[z].add = 0;
tree[x].ass = inf;
}
if (tree[x].add != 0) {
tree[x + 1].apply(l, y, tree[x].add);
tree[z].apply(y + 1, r, tree[x].add);
tree[x].add = 0;
}
} int n;
vector<node> tree;
inline void push_up(int x, int z) { tree[x].maxx = max(tree[x + 1].maxx, tree[z].maxx); }
void build(int x, int l, int r) {
if (l == r) {
return;
}
int y = (l + r) >> 1;
int z = x + ((y - l + 1) << 1);
build(x + 1, l, y);
build(z, y + 1, r);
push_up(x, z);
} template <typename M>
void build(int x, int l, int r, const vector<M> &v) {
if (l == r) {
tree[x].init(v[l]);
return;
}
int y = (l + r) >> 1;
int z = x + ((y - l + 1) << 1);
build(x + 1, l, y, v);
build(z, y + 1, r, v);
push_up(x, z);
} node get(int x, int l, int r, int ll, int rr) {
if (ll <= l && r <= rr) {
return tree[x];
}
int y = (l + r) >> 1;
int z = x + ((y - l + 1) << 1);
push_down(x, l, r);
node res{};
if (rr <= y)
res = get(x + 1, l, y, ll, rr);
else {
if (ll > y)
res = get(z, y + 1, r, ll, rr);
else
res = unite(get(x + 1, l, y, ll, rr), get(z, y + 1, r, ll, rr));
}
push_up(x, z);
return res;
} template <typename M>
void modify(int x, int l, int r, int ll, int rr, const M &v) {
if (ll <= l && r <= rr) {
tree[x].apply(l, r, v);
return;
}
int y = (l + r) >> 1;
int z = x + ((y - l + 1) << 1);
push_down(x, l, r);
if (ll <= y) modify(x + 1, l, y, ll, rr, v);
if (rr > y) modify(z, y + 1, r, ll, rr, v);
push_up(x, z);
} segtree(int _n) : n(_n) {
assert(n > 0);
tree.resize(2 * n - 1);
build(0, 0, n - 1);
} template <typename M>
segtree(const vector<M> &v) {
n = v.size();
assert(n > 0);
tree.resize(2 * n - 1);
build(0, 0, n - 1, v);
} node get(int ll, int rr) {
assert(0 <= ll && ll <= rr && rr <= n - 1);
return get(0, 0, n - 1, ll, rr);
} node get(int p) {
assert(0 <= p && p <= n - 1);
return get(0, 0, n - 1, p, p);
} template <typename M>
void modify(int ll, int rr, const M &v) {
assert(0 <= ll && ll <= rr && rr <= n - 1);
modify(0, 0, n - 1, ll, rr, v);
} void assign(int x, int l, int r, int ll, int rr, i64 v) {
if (ll <= l && r <= rr) {
tree[x].maxx = tree[x].ass = v;
tree[x].add = 0;
return;
}
int y = (l + r) >> 1;
int z = x + ((y - l + 1) << 1);
push_down(x, l, r);
if (ll <= y)
assign(x + 1, l, y, ll, rr, v);
if (rr > y)
assign(z, y + 1, r, ll, rr, v);
push_up(x, z);
}
}; // root's idx is 0 and the begin of vector is also 0;
// don't forget idx is from 0 to n-1 (equal [--x,--y]) when ask;
int n;
i64 ans(tree_chain<i64> &ch, segtree &t, int x, int y) {
i64 res = 0;
while (ch.top[x] != ch.top[y]) {
if (ch.dep[ch.top[x]] < ch.dep[ch.top[y]]) swap(x, y);
res = max(res, t.get(ch.dfn[ch.top[x]], ch.dfn[x]).maxx);
x = ch.fa[ch.top[x]];
}
if (ch.dep[x] > ch.dep[y]) swap(x, y);
if (x == y) return res;//return
res = max(res, t.get(ch.dfn[x] + 1, ch.dfn[y]).maxx);
return res;
}
void add(tree_chain<i64> &ch, segtree &t, int x, int y, i64 w) {
while (ch.top[x] != ch.top[y]) {
if (ch.dep[ch.top[x]] < ch.dep[ch.top[y]]) swap(x, y);
t.modify(ch.dfn[ch.top[x]], ch.dfn[x], w);
x = ch.fa[ch.top[x]];
}
if (ch.dep[x] > ch.dep[y]) swap(x, y);
if (x == y) return;
t.modify(ch.dfn[x] + 1, ch.dfn[y], w);
}
void assign(tree_chain<i64> &ch, segtree &t, int x, int y, i64 w) {
while (ch.top[x] != ch.top[y]) {
if (ch.dep[ch.top[x]] < ch.dep[ch.top[y]]) swap(x, y);
t.assign(0, 0, n - 1, ch.dfn[ch.top[x]], ch.dfn[x], w);
x = ch.fa[ch.top[x]];
}
if (ch.dep[x] > ch.dep[y]) swap(x, y);
if (x == y) return;
t.assign(0, 0, n - 1, ch.dfn[x] + 1, ch.dfn[y], w);
};
signed main() {
std::ios_base::sync_with_stdio(false);
std::cin.tie(nullptr), std::cout.tie(nullptr);
cin >> n;
vector<vector<pair<int, i64>>> adj(n);
vector<pair<int, int>> g(n);
for (int i = 1, x, y, v; i < n; ++i) {
cin >> x >> y >> v;
--x, --y;
g[i] = {x, y};
adj[x].emplace_back(y, v);
adj[y].emplace_back(x, v);
}
tree_chain<i64> ch(adj, n, 0);
segtree t(ch.val);
string op;
while (cin >> op) {
if (op == "Stop") break;
int u, v;
i64 w;
if (op == "Change")
cin >> u >> w, assign(ch, t, g[u].first, g[u].second, w);
else if (op == "Cover")
cin >> u >> v >> w, assign(ch, t, --u, --v, w);
else if (op == "Add")
cin >> u >> v >> w, add(ch, t, --u, --v, w);
else
cin >> u >> v, cout << ans(ch, t, --u, --v) << endl;
}
return 0;
}

P4315 月下“毛景树”(树链剖分)的更多相关文章

  1. P4315 月下“毛景树”

    P4315 月下"毛景树" 题目描述 毛毛虫经过及时的变形,最终逃过的一劫,离开了菜妈的菜园. 毛毛虫经过千山万水,历尽千辛万苦,最后来到了小小的绍兴一中的校园里. 爬啊爬~爬啊爬 ...

  2. P4315 月下“毛景树” (树链剖分+边剖分+区间覆盖+区间加+区间最大值)

    题目链接:https://www.luogu.org/problem/P4315 题目大意: 有N个节点和N-1条树枝,但节点上是没有毛毛果的,毛毛果都是长在树枝上的.但是这棵“毛景树”有着神奇的魔力 ...

  3. 洛谷P4315 月下“毛景树”

    题目描述 毛毛虫经过及时的变形,最终逃过的一劫,离开了菜妈的菜园. 毛毛虫经过千山万水,历尽千辛万苦,最后来到了小小的绍兴一中的校园里. 爬啊爬~爬啊爬毛毛虫爬到了一颗小小的"毛景树&quo ...

  4. P4315 月下“毛景树”[树剖]

    题目描述 毛毛虫经过及时的变形,最终逃过的一劫,离开了菜妈的菜园. 毛毛虫经过千山万水,历尽千辛万苦,最后来到了小小的绍兴一中的校园里. 爬啊爬~爬啊爬毛毛虫爬到了一颗小小的"毛景树&quo ...

  5. [洛谷P4315] 月下”毛景“树

    题目链接: 点我 题目分析: 树剖.将边权下放到下方点上(为什么要选深度更深的点?一个父亲可能对应多个儿子,但一个儿子只有一个父亲,即可以保证每个点只保存一条边权)成为经典点权+树剖裸题 注意链计算时 ...

  6. 洛谷P4315 月下“毛景树”(树剖+线段树)

    传送门 woc这该死的码农题…… 把每一条边转化为它连接的两点中深度较深的那一个,然后就可以用树剖+线段树对路径进行修改了 然后顺便注意在上面这种转化之后,树剖的时候不能搞$LCA$ 然后是几个注意点 ...

  7. BZOJ 1984: 月下“毛景树” [树链剖分 边权]

    1984: 月下“毛景树” Time Limit: 20 Sec  Memory Limit: 64 MBSubmit: 1728  Solved: 531[Submit][Status][Discu ...

  8. 【BZOJ-1984】月下“毛景树” 树链剖分

    1984: 月下“毛景树” Time Limit: 20 Sec  Memory Limit: 64 MBSubmit: 1314  Solved: 416[Submit][Status][Discu ...

  9. Bzoj 1984: 月下“毛景树” 树链剖分

    1984: 月下“毛景树” Time Limit: 20 Sec  Memory Limit: 64 MBSubmit: 1282  Solved: 410[Submit][Status][Discu ...

随机推荐

  1. 从零搭建Pytorch模型教程(四)编写训练过程--参数解析

    ​  前言 训练过程主要是指编写train.py文件,其中包括参数的解析.训练日志的配置.设置随机数种子.classdataset的初始化.网络的初始化.学习率的设置.损失函数的设置.优化方式的设置. ...

  2. ML第7周学习小结

    本周收获 总结一下本周学习内容: 1.学习了<深入浅出Pandas>的第六章:Pandas分组聚合 6.4 聚合统计 6.5 数据分箱 6.6 分组可视化 博客: pandas:聚合统计. ...

  3. Go中rune类型浅析

    一.字符串简单遍历操作 在很多语言中,字符串都是不可变类型,golang也是. 1.访问字符串字符 如下代码,可以实现访问字符串的单个字符和单个字节 package main import ( &qu ...

  4. Java开发学习(二)----IOC、DI入门案例

    一.IOC入门案例 1.1 思路分析 (1)Spring是使用容器来管理bean对象的,那么管什么? 主要管理项目中所使用到的类对象,比如(Service和Dao) (2)如何将被管理的对象告知IOC ...

  5. Redis - 读写模式 - 缓存一致性

    Cache Aside Pattern(旁路缓存模式) 读:从cache中读取数据,若读取到则直接返回:cache中不存在则去database中读取,然后更新到cache. 写:先更新database ...

  6. Elasticsearch学习系列二(基础操作)

    本文将分为3块讲解Es的基础操作.分别为:索引(index).映射(mapping).文档(document). 索引操作 创建索引库 语法: PUT /索引名称{ "settings&qu ...

  7. Java 将HTML转为XML

    本文介绍如何通过Java后端程序代码来展示如何将html转为XML.此功能通过采用Word API- Free Spire.Doc for Java 提供的Document.saveToFile()方 ...

  8. 【机器学习】数据准备--python爬虫

    前言 我们在学习机器学习相关内容时,一般是不需要我们自己去爬取数据的,因为很多的算法学习很友好的帮助我们打包好了相关数据,但是这并不代表我们不需要进行学习和了解相关知识.在这里我们了解三种数据的爬取: ...

  9. Kubebuilder模块

    CRD创建 Group表示CRD所属的组,它可以支持多种不同版本.不同类型的资源构建,Version表示CRD的版本号,Kind表示CRD的类型 kubebuilder create api --gr ...

  10. C# Winform程序界面优化实例

    进入移动互联网时代以来,Windows桌面开发已经很久不碰了.之前就是从做Windows开发入行的. 当年,还是C++ VC6, MFC的时代.那时候开发要查的是MSDN :-).内存要自己管理, 排 ...