题目
月下“毛景树”
题目描述
毛毛虫经过及时的变形,最终逃过的一劫,离开了菜妈的菜园。 毛毛虫经过千山万水,历尽千辛万苦,最后来到了小小的绍兴一中的校园里。
爬啊爬~爬啊爬 毛毛虫爬到了一颗小小的“毛景树”下面,发现树上长着他最爱吃的毛毛果 “毛景树”上有N个节点和N-1条树枝,但节点上是没有毛毛果的,毛毛果都是长在树枝上的。但是这棵“毛景树”有着神奇的魔力,他能改变树枝上毛毛果的个数:
-
Change k w:将第k条树枝上毛毛果的个数改变为w个。
-
Cover u v w:将节点u与节点v之间的树枝上毛毛果的个数都改变为w个。
-
Add u v w:将节点u与节点v之间的树枝上毛毛果的个数都增加w个。 由于毛毛虫很贪,于是他会有如下询问:
-
Max u v:询问节点u与节点v之间树枝上毛毛果个数最多有多少个。
输入格式
第一行一个正整数N。
接下来N-1行,每行三个正整数Ui,Vi和Wi,第i+1行描述第i条树枝。表示第i条树枝连接节点Ui和节点Vi,树枝上有Wi个毛毛果。 接下来是操作和询问,以“Stop”结束。
输出格式
对于毛毛虫的每个询问操作,输出一个答案。
样例 #1
样例输入 #1
4
1 2 8
1 3 7
3 4 9
Max 2 4
Cover 2 4 5
Add 1 4 10
Change 1 16
Max 2 4
Stop
样例输出 #1
9
16
提示
1<=N<=100,000,操作+询问数目不超过100,000。
保证在任意时刻,所有树枝上毛毛果的个数都不会超过10^9个。
思路
树链剖分+线段树。
此题维护边权和,只需将边权转化成点权即可。
对于每条边,我们将其权值转化为深度较深的点的点权,这样可以一一对应。
区间查询是,两点的 LCA 的点权是不可以取的,它所对应的边并不在两点路径上。
所以树链剖分的最后一次操作,区间应为
i
d
[
x
]
+
1
∼
i
d
[
y
]
id[x]+1 \sim id[y]
id[x]+1∼id[y]。
接下来就是码码码了。
要考虑清楚懒标记的下传。区间覆盖的懒标记优先级更高。如果区间覆盖要下传,左右儿子区间加的懒标记就要被清零了!
然后又调了好长时间,结果发现单点修改时下标搞错了,应该是树剖后的 i d [ x ] id[x] id[x],而非 x x x…
代码
#include <bits/stdc++.h>
#define rep(i, a, b) for (register int i(a); i <= b; ++i)
#define per(i, a, b) for (register int i(a); i >= b; --i)
#define FILE(s) freopen(s".in", "r", stdin), freopen(s".out", "w", stdout)
#define mem(a, x) memset(a, x, sizeof a)
#define pb push_back
#define umap unordered_map
#define pqueue priority_queue
#define mp make_pair
#define PI acos(-1)
//#define int long long
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
int n, dep[100005], siz[100005], son[100005], top[100005], father[100005], a[100005], id[100005], w[100005], tot;
vector <int> e[100005];
struct enode {
int x, y, z;
} ed[100005];
template <typename _T>
void rd(_T &x) {
int f = 1; x = 0;
char s = getchar();
while (s > '9' || s < '0') {if (s == '-') f = -1; s = getchar();}
while (s >= '0' && s <= '9') x = (x<<3)+(x<<1)+(s^48), s = getchar();
x *= f;
}
template <typename _T>
void write(_T x) {
if (x < 0) putchar('-'), x = -x;
if (x > 9) write(x/10);
putchar(x%10+'0');
return ;
}
struct seg {
int tr[400005], tag[400005], tag2[400005];
#define ls k<<1
#define rs k<<1|1
inline void pushup(int k) {
tr[k] = max(tr[ls], tr[rs]);
return ;
}
inline void pushdown(int k) {
int x = tag2[k];
if (x >= 0) tag2[ls] = tag2[rs] = x, tr[ls] = tr[rs] = x, tag[ls] = tag[rs] = 0;
tag2[k] = -1;
x = tag[k];
tag[k] = 0;
tag[ls] += x, tag[rs] += x;
tr[ls] += x, tr[rs] += x;
return ;
}
void build(int k, int l, int r) {
tag2[k] = -1;
if (l == r) {
tr[k] = w[l];
return ;
}
int mid = (l+r) >> 1;
build(ls, l, mid); build(rs, mid+1, r);
pushup(k);
return ;
}
void modify_p(int k, int l, int r, int pos, int c) {
if (l == r) {
tr[k] = c;
return ;
}
pushdown(k);
int mid = (l+r) >> 1;
if (pos <= mid) modify_p(ls, l, mid, pos, c);
else modify_p(rs, mid+1, r, pos, c);
pushup(k);
return ;
}
void modify(int k, int l, int r, int L, int R, int c) {
if (L > R) return ;
if (l >= L && r <= R) {
tr[k] = c;
tag2[k] = c;
tag[k] = 0;
return ;
}
pushdown(k);
int mid = (l+r) >> 1;
if (L <= mid) modify(ls, l, mid, L, R, c);
if (R > mid) modify(rs, mid+1, r, L, R, c);
pushup(k);
return ;
}
void add(int k, int l, int r, int L, int R, int c) {
if (L > R) return ;
if (l >= L && r <= R) {
tr[k] += c;
tag[k] += c;
return ;
}
pushdown(k);
int mid = (l+r) >> 1;
if (L <= mid) add(ls, l, mid, L, R, c);
if (R > mid) add(rs, mid+1, r, L, R, c);
pushup(k);
return ;
}
int query(int k, int l, int r, int L, int R) {
if (L > R) return -1;
if (l >= L && r <= R) return tr[k];
pushdown(k);
int mid = (l+r) >> 1, ret = 0;
if (L <= mid) ret = max(ret, query(ls, l, mid, L, R));
if (R > mid) ret = max(ret, query(rs, mid+1, r, L, R));
return ret;
}
} Tr;
void dfs1(int x, int fa) {
dep[x] = dep[fa]+1;
father[x] = fa;
siz[x] = 1;
int maxn = 0;
for (auto y : e[x]) {
if (y == fa) continue;
dfs1(y, x);
siz[x] += siz[y];
if (maxn < siz[y]) maxn = siz[y], son[x] = y;
}
return ;
}
void dfs2(int x, int fa, int tp) {
top[x] = tp;
id[x] = ++tot;
w[tot] = a[x];
if (son[x] == 0) return ;
dfs2(son[x], x, tp);
for (auto y : e[x]) {
if (y == fa || y == son[x]) continue;
dfs2(y, x, y);
}
return ;
}
int query_road(int x, int y) {
int ret = 0;
while (top[x] != top[y]) {
if (dep[top[x]] < dep[top[y]]) x ^= y ^= x ^= y;
ret = max(ret, Tr.query(1, 1, n, id[top[x]], id[x]));
x = father[top[x]];
}
if (dep[x] > dep[y]) x ^= y ^= x ^= y;
ret = max(ret, Tr.query(1, 1, n, id[x]+1, id[y]));
return ret;
}
void cover_road(int x, int y, int z) {
while (top[x] != top[y]) {
if (dep[top[x]] < dep[top[y]]) x ^= y ^= x ^= y;
Tr.modify(1, 1, n, id[top[x]], id[x], z);
x = father[top[x]];
}
if (dep[x] > dep[y]) x ^= y ^= x ^= y;
Tr.modify(1, 1, n, id[x]+1, id[y], z);
return ;
}
void modify_road(int x, int y, int z) {
while (top[x] != top[y]) {
if (dep[top[x]] < dep[top[y]]) x ^= y ^= x ^= y;
Tr.add(1, 1, n, id[top[x]], id[x], z);
x = father[top[x]];
}
if (dep[x] > dep[y]) x ^= y ^= x ^= y;
Tr.add(1, 1, n, id[x]+1, id[y], z);
return ;
}
int main() {
rd(n);
rep(i, 1, n-1) {
int x, y, z; rd(x), rd(y), rd(z);
e[x].pb(y), e[y].pb(x);
ed[i].x = x, ed[i].y = y, ed[i].z = z;
}
dfs1(1, 0);
rep(i, 1, n-1) {
if (ed[i].x == father[ed[i].y]) a[ed[i].y] = ed[i].z;
else a[ed[i].x] = ed[i].z;
}
dfs2(1, 0, 1);
Tr.build(1, 1, n);
while (true) {
char s[11]; scanf("%s", s);
if (s[0] == 'S') break;
if (s[0] == 'M') {
int u, v; rd(u), rd(v);
printf("%d\n", query_road(u, v));
} else if (s[0] == 'C' && s[1] == 'o') {
int u, v, w; rd(u), rd(v), rd(w);
cover_road(u, v, w);
} else if (s[0] == 'C' && s[1] == 'h') {
int u, w; rd(u), rd(w);
int x;
if (ed[u].x == father[ed[u].y]) x = ed[u].y;
else x = ed[u].x;
Tr.modify_p(1, 1, n, id[x], w);
} else {
int u, v, w; rd(u), rd(v), rd(w);
modify_road(u, v, w);
}
}
return 0;
}