BZOJ 2157 旅游 (树链剖分)
题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=2157
这道题给出的是边权,所以我们要把它转换成点权。
题目要求操作:
1.查询景区u,v之间所有桥愉悦值的总和
2.查询景区u,v之间桥愉悦值的最大值
3.查询景区u,v之间桥愉悦值的最小值
4.把景区u,v之间桥的愉悦值全部-1
5.把第i座桥的愉悦值修改为C
思路:因为城市任意两点之间只有一条路径,于是可以把这座城市看成是一颗树,用树链剖分可以进行上面需要的操作。
细节:
1.向下更新时,把左右孩子的lazy标记异或1,而不是直接赋1
2.区间值-1时,把维护的suml取反,maxl,minl交换后取反即可
3.所谓的桥,即是我们用邻接表存储的边,这里我们从下标2开始存储边,因为存储的是无向边,所以我们只需把桥的编号 i << 1, i << 1 | 1得到的即是邻接表edge的下标
(例如第一条桥肯定是edge[2],edge[3]),这样我们就能找到每条桥对应的点了(然后比较一下两条边的dep,这条桥的权值属于深度较大的点),这样我们就成功地把边权转换为了点权
4.景区u,v之间进行操作时,当两个点u,v跳到同一条重链时,深度较小的点的权值不应被考虑,因为操作的是u,v之间的边权,深度较小点的边权肯定不在u,v之间
#include <cmath> #include <cstdio> #include <algorithm> #include <iostream> #include <cstring> #include <ctype.h> #include <map> #include <vector> #include <set> #include <bitset> #define lson rt << 1, l, mid #define rson rt << 1 | 1, mid + 1, r #define L(rt) rt << 1 #define R(rt) rt << 1 | 1 #define INF 0x7fffffff #define eps 1e-9 #define pi acos(-1.0) using namespace std; typedef long long ll; static const int MAX_N = 1e5 + 5; static const int Mod = 10007; struct Edge { int to, w, next; }edge[MAX_N << 1]; int head[MAX_N]; //链式前向星 int a[MAX_N]; int siz[MAX_N], son[MAX_N], top[MAX_N], fa[MAX_N], id[MAX_N], dep[MAX_N], rk[MAX_N]; int cnt, tot; void dfs1(int u, int f, int d) { //第一次dfs得到重儿子 siz[u] = 1; son[u] = 0; fa[u] = f; dep[u] = d; for (int i = head[u]; i; i = edge[i].next) { int v = edge[i].to; if (v == f) continue; //不走重复路 a[v] = edge[i].w; dfs1(v, u, d + 1); siz[u] += siz[v]; if (siz[v] > siz[son[u]]) son[u] = v; } } void dfs2(int u, int t) { //将重儿子连接成重链,轻儿子连接成轻链(得到区间) top[u] = t; id[u] = ++cnt; rk[cnt] = u; if (son[u]) dfs2(son[u], t); //优先处理重链 for (int i = head[u]; i; i = edge[i].next) { int v = edge[i].to; if (v != son[u] && v != fa[u]) dfs2(v, v); } } int getPoint(int u) { return dep[edge[u << 1].to] > dep[edge[u << 1 | 1].to] ? edge[u << 1].to : edge[u << 1 | 1].to; } struct Node { int l, r; int minl, maxl, suml, tag; }T[MAX_N << 2]; void prework() { memset(head, 0, sizeof(head)); cnt = 0; tot = 1; } void addEdge(int u, int v, int w) { edge[++tot].to = v; edge[tot].next = head[u]; edge[tot].w = w; head[u] = tot; } void pushUp(int rt) { T[rt].suml = T[L(rt)].suml + T[R(rt)].suml; T[rt].maxl = max(T[L(rt)].maxl, T[R(rt)].maxl); T[rt].minl = min(T[L(rt)].minl, T[R(rt)].minl); } void build(int rt, int l, int r) { T[rt].l = l; T[rt].r = r; T[rt].tag = 0; if (l == r) { T[rt].maxl = T[rt].minl = T[rt].suml = a[rk[l]]; return; } int mid = l + r >> 1; build(lson); build(rson); pushUp(rt); } void pushNow(int rt) { swap(T[rt].maxl, T[rt].minl); T[rt].maxl = -T[rt].maxl; T[rt].minl = -T[rt].minl; T[rt].suml = -T[rt].suml; T[rt].tag ^= 1; } void pushDown(int rt) { if (T[rt].tag) { pushNow(L(rt)); pushNow(R(rt)); T[rt].tag = 0; } } void updatePoint(int rt, int pos, int c) { if (T[rt].l == T[rt].r) { T[rt].maxl = T[rt].minl = T[rt].suml = c; return; } pushDown(rt); int mid = T[rt].l + T[rt].r >> 1; if (pos <= mid) updatePoint(L(rt), pos, c); else updatePoint(R(rt), pos, c); pushUp(rt); } void updateInterval(int rt, int ql, int qr) { if (T[rt].l > qr || T[rt].r < ql) return; if (T[rt].l >= ql && T[rt].r <= qr) { pushNow(rt); return; } pushDown(rt); int mid = T[rt].l + T[rt].r >> 1; if (ql <= mid) updateInterval(L(rt), ql, qr); if (qr > mid) updateInterval(R(rt), ql, qr); pushUp(rt); } int queryMax(int rt, int ql, int qr) { if (T[rt].l > qr || T[rt].r < ql) return -INF; if (T[rt].l >= ql && T[rt].r <= qr) return T[rt].maxl; pushDown(rt); int ans = -INF; int mid = T[rt].l + T[rt].r >> 1; if (ql <= mid) ans = max(ans, queryMax(L(rt), ql, qr)); if (qr > mid) ans = max(ans, queryMax(R(rt), ql, qr)); return ans; } int querySum(int rt, int ql, int qr) { if (T[rt].l > qr || T[rt].r < ql) return 0; if (T[rt].l >= ql && T[rt].r <= qr) return T[rt].suml; pushDown(rt); int mid = T[rt].l + T[rt].r >> 1; int ans = 0; if (ql <= mid) ans += querySum(L(rt), ql, qr); if (qr > mid) ans += querySum(R(rt), ql, qr); return ans; } int queryMin(int rt, int ql, int qr) { if (T[rt].l > qr || T[rt].r < ql) return INF; if (T[rt].l >= ql && T[rt].r <= qr) return T[rt].minl; pushDown(rt); int ans = INF; int mid = T[rt].l + T[rt].r >> 1; if (ql <= mid) ans = min(ans, queryMin(L(rt), ql, qr)); if (qr > mid) ans = min(ans, queryMin(R(rt), ql, qr)); return ans; } void updatePathVal(int u, int v) { while (top[u] != top[v]) { if (dep[top[u]] < dep[top[v]]) swap(u, v); updateInterval(1, id[top[u]], id[u]); u = fa[top[u]]; } if (dep[u] > dep[v]) swap(u, v); updateInterval(1, id[u] + 1, id[v]); } int queryPathMax(int u, int v) { int ans = -INF; while (top[u] != top[v]) { if (dep[top[u]] < dep[top[v]]) swap(u, v); ans = max(ans, queryMax(1, id[top[u]], id[u])); u = fa[top[u]]; } if (dep[u] > dep[v]) swap(u, v); ans = max(ans, queryMax(1, id[u] + 1, id[v])); return ans; } int queryPathSum(int u, int v) { int ans = 0; while (top[u] != top[v]) { if (dep[top[u]] < dep[top[v]]) swap(u, v); ans += querySum(1, id[top[u]], id[u]); u = fa[top[u]]; } if (dep[u] > dep[v]) swap(u, v); ans += querySum(1, id[u] + 1, id[v]); return ans; } int queryPathMin(int u, int v) { int ans = INF; while (top[u] != top[v]) { if (dep[top[u]] < dep[top[v]]) swap(u, v); ans = min(ans, queryMin(1, id[top[u]], id[u])); u = fa[top[u]]; } if (dep[u] > dep[v]) swap(u, v); ans = min(ans, queryMin(1, id[u] + 1, id[v])); return ans; } void mainwork(){ /*freopen("input.txt", "r", stdin); freopen("output.txt", "w", stdout);*/ int n, q; scanf("%d", &n); for (int i = 1; i < n; ++i) { int u, v, w; scanf("%d%d%d", &u, &v, &w); ++u, ++v; addEdge(u, v, w); addEdge(v, u, w); } dfs1(1, 1, 1); dfs2(1, 1); build(1, 1, n); scanf("%d", &q); while (q--) { char opt[5]; int u, v, c; scanf("%s%d%d", opt, &u, &v); if (opt[0] == 'C') updatePoint(1, id[getPoint(u)], v); else if (opt[0] == 'N') updatePathVal(u + 1, v + 1); else if (opt[1] == 'U') printf("%d\n", queryPathSum(u + 1, v + 1)); else if (opt[1] == 'I') printf("%d\n", queryPathMin(u + 1, v + 1)); else printf("%d\n", queryPathMax(u + 1, v + 1)); } } int main() { prework(); mainwork(); return 0; }