大致题意:给定一棵树,点有权值。现在需要维护两种操作:1,a,b1,a,b1,a,b查询树上aaa到bbb间简单路径上最大的点权;2,a,b2,a,b2,a,b针对树上所有与点aaa相邻的点,使其点权+b+b+b,不包括aaa本身。
解:
考虑用重链剖分,此时操作111很好查询,用线段树维护DFSDFSDFS序即可。
而对于操作222,本来我想着针对aaa的所有儿子,每次跳即可。
int cnt = (u == 1 ? g[u].size() : g[u].size() - 1);
int now = 0;
int node = hl.getSon(u);
int lim = hl.getDepth(node);
while (now < cnt) {
if (hl.getDepth(node) == lim) {
t.change(hl.getDfn(node), hl.getDfn(node), v);
d[hl.getDfn(node)] += v;
now++;
}
node = hl.getRnk(hl.getBottom(node) + 1);
}
写完了还没意识到其本质跟遍历g[u]g[u]g[u]没区别,必定超时的。然后就超时了。
从线段树的懒标记可以得到启发:对于uuu的轻儿子,其作为一条新链的toptoptop,我们不用立即去更新,而是给其父节点uuu打上标记tag[u]tag[u]tag[u];而对于uuu的重儿子和其父亲,我们正常更新。在查询的时候,正常跳跃更新答案。但是在到达链顶toptoptop的时候,由于其是新链的链顶,那么其父亲的重儿子必定不是它。我们查询一下其父亲是否存在tagtagtag,如果有tagtagtag的话,那就代表此toptoptop应当被更新过。于是再单独针对链顶更新一次。
当查询的u,vu,vu,v位于同链的时候,我们需要额外注意:假设uuu深度较小,我们需要考虑其是否可能是其父亲的轻儿子,即
if (sp.getParent(u) && sp.getTop(u) == u) {
ans = max(ans, a[u] + tag[sp.getParent(u)]);
}
代码如下:
#include<bits/stdc++.h>
#define endl '\n'
#define pii pair<int,int>
#define int long long
using namespace std;
const double eps = 1e-10;
const int mod = 1e9 + 7;
int lowbit(int x) {
return x & (-x);
}
int ONECNT(int x) {
return __builtin_popcountll(x);
}
int get(int x, int pos) {
return (x >> pos) & 1;
}
int qp(int a, int b, int p) {
int res = 1;
while (b) {
if (b & 1) {
res = res % p * (a % p) % p;
}
b >>= 1;
a = a % p * (a % p) % p;
}
return res % p;
}
class HeavyLight {
private:
int n;
int timer;
vector<vector<int>> &adj;
vector<int> fa, dep, son, top, dfn, rnk, siz;
// 第一次 DFS: 求 fa(x), dep(x), siz(x), son(x)
int dfs1(int u, int p) {
fa[u] = p;
dep[u] = (p ? dep[p] + 1 : 0);
siz[u] = 1;
int maxSize = 0;
for (int v: adj[u]) {
if (v == p) continue;
int subsz = dfs1(v, u);
if (subsz > maxSize) {
maxSize = subsz;
son[u] = v;
}
siz[u] += subsz;
}
return siz[u];
}
// 第二次 DFS: 求 top(x), dfn(x), rnk(x)
void dfs2(int u, int tp) {
top[u] = tp;
dfn[u] = ++timer;
rnk[timer] = u;
if (son[u] != 0)
dfs2(son[u], tp); //优先对重儿子dfs 保证dfs序连续
for (int v: adj[u]) {
if (v == fa[u] || v == son[u]) continue;
dfs2(v, v);
}
}
public:
HeavyLight(int _n, vector<vector<int>> &_adj)
: n(_n), adj(_adj), timer(0) {
fa.assign(n + 1, 0);
dep.assign(n + 1, 0);
son.assign(n + 1, 0);
top.assign(n + 1, 0);
dfn.assign(n + 1, 0);
rnk.assign(n + 1, 0);
siz.assign(n + 1, 0);
}
// 初始化,root一般为1
void init(int root = 1) {
dfs1(root, 0);
dfs2(root, root);
}
// 路径拆分: 从 u 到 v 分成若干链段,op 为区间操作
template<typename OP>
void processPath(int u, int v, OP op) {
while (top[u] != top[v]) {
if (dep[top[u]] > dep[top[v]]) {
op(dfn[top[u]], dfn[u]);
u = fa[top[u]];
} else {
op(dfn[top[v]], dfn[v]);
v = fa[top[v]];
}
}
if (dep[u] > dep[v]) swap(u, v);
op(dfn[u], dfn[v]);
}
// 求最近公共祖先
int lca(int u, int v) const {
while (top[u] != top[v]) {
if (dep[top[u]] > dep[top[v]]) u = fa[top[u]];
else v = fa[top[v]];
}
return dep[u] < dep[v] ? u : v;
}
// 访问器
int getDfn(int x) const { return dfn[x]; }
int getRnk(int i) const { return rnk[i]; }
int getTop(int x) const { return top[x]; }
int getParent(int x) const { return fa[x]; }
int getDepth(int x) const { return dep[x]; }
int getSubtreeSize(int x) const { return siz[x]; }
int getBottom(int x) const { return getDfn(x) + getSubtreeSize(x) - 1; }
int getSon(int x) const { return son[x]; }
};
// 用法示例:
// int main() {
// int n; cin >> n;
// vector<vector<int>> g(n+1);
// for (int i = 1; i < n; i++) {
// int u, v; cin >> u >> v;
// g[u].push_back(v);
// g[v].push_back(u);
// }
// HeavyLight hld(n, g);
// hld.init(1);
// auto op = [&](int l, int r) {
// // seg.query(l, r);
// };
// hld.processPath(u, v, op);
// return 0;
// }
class tree { //支持区间修改 区间最值查询
private:
int n;
vector<int> t, lazy;
void build(int x, int l, int r, const vector<int> &arr) {
if (l == r) {
t[x] = arr[l];
return;
}
int mid = (l + r) >> 1;
build(x << 1, l, mid, arr);
build(x << 1 | 1, mid + 1, r, arr);
t[x] = max(t[x << 1], t[x << 1 | 1]);
}
void pd(int x, int l, int r) {
if (lazy[x]) {
lazy[x << 1] += lazy[x];
lazy[x << 1 | 1] += lazy[x];
int mid = (l + r) >> 1;
t[x << 1] += lazy[x];
t[x << 1 | 1] += lazy[x];
lazy[x] = 0;
}
}
void change(int x, int l, int r, int ll, int rr, int val) {
if (ll <= l && rr >= r) {
lazy[x] += val;
t[x] += val;
return;
}
if (rr < l || ll > r) return;
pd(x, l, r);
int mid = (l + r) >> 1;
change(x << 1, l, mid, ll, rr, val);
change(x << 1 | 1, mid + 1, r, ll, rr, val);
t[x] = max(t[x << 1], t[x << 1 | 1]);
}
int que(int x, int l, int r, int ll, int rr) {
if (ll <= l && rr >= r) {
return t[x];
}
if (ll > r || rr < l) return LLONG_MIN;
pd(x, l, r);
int mid = (l + r) >> 1;
return max(que(x << 1, l, mid, ll, rr), que(x << 1 | 1, mid + 1, r, ll, rr));
}
public:
tree(int size) {
n = size;
t.resize(size * 4);
lazy.resize(size * 4);
}
void build(const vector<int> &arr) {
build(1, 1, n, arr);
}
void change(int l, int r, int val) {
change(1, 1, n, l, r, val);
}
int que(int l, int r) {
return que(1, 1, n, l, r);
}
};
void solve() {
int n, q;
cin >> n >> q;
vector<int> a(n + 1);
for (int i = 1; i <= n; i++) {
cin >> a[i];
}
vector<vector<int>> g(n + 1);
for (int i = 1; i < n; i++) {
int u, v;
cin >> u >> v;
g[u].push_back(v);
g[v].push_back(u);
}
vector<int> tag(n + 1);
HeavyLight sp(n, g);
sp.init(1);
tree t(n);
vector<int> d(n + 1);
for (int i = 1; i <= n; i++) {
d[sp.getDfn(i)] = a[i];
}
t.build(d);
while (q--) {
int x, u, v;
cin >> x >> u >> v;
if (x == 1) {
int ans = 0;
while (sp.getTop(u) != sp.getTop(v)) {
if (sp.getDepth(sp.getTop(u)) < sp.getDepth(sp.getTop(v))) {
swap(u, v);
}
if (sp.getDfn(sp.getTop(u)) + 1 <= sp.getDfn(u)) {
ans = max(ans, t.que(sp.getDfn(sp.getTop(u)) + 1, sp.getDfn(u)));
}
int hd = sp.getTop(u);
if (sp.getParent(hd)) {
ans = max(ans, a[hd] + tag[sp.getParent(hd)]);
}
u = sp.getParent(hd);
}
if (sp.getDfn(u) > sp.getDfn(v))
swap(u, v);
if (sp.getParent(u) && sp.getTop(u) == u) {
ans = max(ans, a[u] + tag[sp.getParent(u)]);
}
ans = max(ans, t.que(sp.getDfn(u), sp.getDfn(v)));
cout << ans << endl;
} else {
int hvson = sp.getSon(u);
if (hvson) {
t.change(sp.getDfn(hvson), sp.getDfn(hvson), v);
d[sp.getDfn(hvson)] += v;
a[hvson] += v;
}
int fa = sp.getParent(u);
if (fa) {
t.change(sp.getDfn(fa), sp.getDfn(fa), v);
d[sp.getDfn(fa)] += v;
a[fa] += v;
}
tag[u] += v;
}
}
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
int T = 1;
cin >> T;
while (T--) {
solve();
}
}
1009 苹果树 题解记录&spm=1001.2101.3001.5002&articleId=149860116&d=1&t=3&u=fdaa36d3d00a4a0e94e4321986e661c4)
1269

被折叠的 条评论
为什么被折叠?



