From ed0d5cf6e7ddf6792a07f27b449ce8c58a28e3db Mon Sep 17 00:00:00 2001 From: hanyixuanten Date: Thu, 29 Oct 2026 12:30:27 +0000 Subject: [PATCH] new file: P1505.cpp --- P1505.cpp | 156 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ P1505.md | 72 +++++++++++++++++++++++++ 2 files changed, 228 insertions(+) create mode 100644 P1505.cpp create mode 100644 P1505.md diff --git a/P1505.cpp b/P1505.cpp new file mode 100644 index 0000000..14e4034 --- /dev/null +++ b/P1505.cpp @@ -0,0 +1,156 @@ +#include +using namespace std; +int n; +vector> fri[200005]; +pair edge[200005]; +int a[200005]; +int fa[200005]; +int dfn[200005]; +int nowdfn; +int cnt[200005]; +int son[200005]; +int top[200005]; +int dep[200005]; +int m; +struct SEG{ + int num[3][800005]; + bool lt[800005]; + void pu(int now, int op) { + if(op == 0) num[op][now] = num[op][now * 2] + num[op][now * 2 + 1]; + else if(op == 1) num[op][now] = max(num[op][now * 2], num[op][now * 2 + 1]); + else num[op][now] = min(num[op][now * 2], num[op][now * 2 + 1]); + } + void pu(int now) {pu(now, 0), pu(now, 1), pu(now, 2);} + void dorev(int now) { + lt[now] ^= 1; + num[0][now] = -num[0][now]; + int tmp = num[1][now]; + num[1][now] = -num[2][now]; + num[2][now] = -tmp; + } + void pd(int now, int nl, int nr) { + if(!lt[now]) return; + dorev(now * 2); + dorev(now * 2 + 1); + lt[now] = 0; + } + void edit(int now, int nl, int nr, int l, int nn) { + if(l < nl || l > nr) return; + if(nl == nr) { + num[0][now] = nn, num[1][now] = nn, num[2][now] = nn; + return; + } + int nmid = (nl + nr) >> 1; + pd(now, nl, nr); + edit(now * 2, nl, nmid, l, nn); + edit(now * 2 + 1, nmid + 1, nr, l, nn); + pu(now); + } + void rev(int now, int nl, int nr, int l, int r) { + if(nr < l || nl > r) return; + if(l <= nl && nr <= r) { + dorev(now); + return; + } + pd(now, nl, nr); + int nmid = (nl + nr) >> 1; + rev(now * 2, nl, nmid, l, r); + rev(now * 2 + 1, nmid + 1, nr, l, r); + pu(now); + } + int query(int now, int nl, int nr, int l, int r, int op) { + if(nr < l || nl > r) return (op==2)?INT_MAX:((op==1)?INT_MIN:0); + if(l <= nl && nr <= r) { + return num[op][now]; + } + int nmid = (nl + nr) >> 1; + pd(now, nl, nr); + if(op == 0) return query(now * 2, nl, nmid, l, r, op) + query(now * 2 + 1, nmid + 1, nr, l, r, op); + else if(op == 1) return max(query(now * 2, nl, nmid, l, r, op), query(now * 2 + 1, nmid + 1, nr, l, r, op)); + else return min(query(now * 2, nl, nmid, l, r, op), query(now * 2 + 1, nmid + 1, nr, l, r, op)); + } +}seg; +void dfs1(int now, int from) { + cnt[now] = 1; + for(pair i : fri[now]) { + if(i.second == from) continue; + a[i.second] = i.first; // 边权转点权 + fa[i.second] = now; + dep[i.second] = dep[now] + 1; + dfs1(i.second, now); + cnt[now] += cnt[i.second]; + if(cnt[i.second] > cnt[son[now]]) son[now] = i.second; + } +} +void dfs2(int now, int from) { + dfn[now] = ++nowdfn; + seg.edit(1, 1, n, nowdfn, a[now]); + top[now] = from; + if(son[now]) dfs2(son[now], from); + for(pair i : fri[now]) { + if(i.second == son[now] || i.second == fa[now]) continue; + dfs2(i.second, i.second); + } +} +void rev(int u, int v) { + while(top[u] != top[v]) { + if(dep[top[u]] < dep[top[v]]) swap(u, v); + seg.rev(1, 1, n, dfn[top[u]], dfn[u]); + u = fa[top[u]]; + } + if(dep[u] < dep[v]) swap(u, v); + if(dfn[v] + 1 <= dfn[u]) + seg.rev(1, 1, n, dfn[v] + 1, dfn[u]); +} +int f(int u, int v, int op) { + int ans = 0; + if(op == 1) ans = INT_MIN; + if(op == 2) ans = INT_MAX; + while(top[u] != top[v]) { + if(dep[top[u]] < dep[top[v]]) swap(u, v); + if(op == 0) ans += seg.query(1, 1, n, dfn[top[u]], dfn[u], 0); + else if(op == 1) ans = max(ans, seg.query(1, 1, n, dfn[top[u]], dfn[u], 1)); + else ans = min(ans, seg.query(1, 1, n, dfn[top[u]], dfn[u], 2)); + u = fa[top[u]]; + } + if(dep[u] < dep[v]) swap(u, v); + if(dfn[v] + 1 <= dfn[u]) { + if(op == 0) ans += seg.query(1, 1, n, dfn[v] + 1, dfn[u], 0); + else if(op == 1) ans = max(ans, seg.query(1, 1, n, dfn[v] + 1, dfn[u], 1)); + else ans = min(ans, seg.query(1, 1, n, dfn[v] + 1, dfn[u], 2)); + } + return ans; +} +int main() { + scanf("%d", &n); + for(int i = 1, u, v, w; i < n; ++i) { + scanf("%d%d%d", &u, &v, &w); + u++, v++; + fri[u].push_back({w, v}); + fri[v].push_back({w, u}); + edge[i] = {u, v}; + } + dfs1(1, 0); + dfs2(1, 1); + scanf("%d", &m); + while(m--) { + char op[5]; + int u, v; + scanf("%s%d%d", op, &u, &v); + if(op[0] == 'C') { + pair ed = edge[u]; + if(dep[ed.first] > dep[ed.second]) u = ed.first; + else u = ed.second; + seg.edit(1, 1, n, dfn[u], v); + } else if(op[0] == 'N') { + rev(u + 1, v + 1); + } else if(op[0] == 'S') { + printf("%d\n", f(u + 1, v + 1, 0)); + } else if(op[1] == 'A') { + printf("%d\n", f(u + 1, v + 1, 1)); + } else { + printf("%d\n", f(u + 1, v + 1, 2)); + } + } + return 0; +} \ No newline at end of file diff --git a/P1505.md b/P1505.md new file mode 100644 index 0000000..946f92a --- /dev/null +++ b/P1505.md @@ -0,0 +1,72 @@ +# P1505 [国家集训队] 旅游 + +## 题目背景 + +Ray 乐忠于旅游,这次他来到了 T 城。T 城是一个水上城市,一共有 $n$ 个景点,有些景点之间会用一座桥连接。为了方便游客到达每个景点但又为了节约成本,T 城的任意两个景点之间有且只有一条路径。换句话说, T 城中只有 $n-1$ 座桥。 + +Ray 发现,有些桥上可以看到美丽的景色,让人心情愉悦,但有些桥狭窄泥泞,令人烦躁。于是,他给每座桥定义一个愉悦度 $w$,也就是说,Ray 经过这座桥会增加 $w$ 的愉悦度,这或许是正的也可能是负的。有时,Ray 看待同一座桥的心情也会发生改变。 + +现在,Ray 想让你帮他计算从 $u$ 景点到 $v$ 景点能获得的总愉悦度。有时,他还想知道某段路上最美丽的桥所提供的最大愉悦度,或是某段路上最糟糕的一座桥提供的最低愉悦度。 + +## 题目描述 + +给定一棵 $n$ 个节点的树,边带权,点的编号为 $0 \sim n-1$,需要支持五种操作: + +- `C i w` 将输入的第 $i$ 条边权值改为 $w$; +- `N u v` 将 $u,v$ 节点之间的边权都变为相反数; +- `SUM u v` 询问 $u,v$ 节点之间边权和; +- `MAX u v` 询问 $u,v$ 节点之间边权最大值; +- `MIN u v` 询问 $u,v$ 节点之间边权最小值。 + +保证任意时刻所有边的权值都在 $[-1000,1000]$ 内。 + +## 输入格式 + +第一行一个正整数 $n$,表示节点个数。 +接下来 $n-1$ 行,每行三个整数 $u,v,w$,表示 $u,v$ 之间有一条权值为 $w$ 的边,描述这棵树。 +然后一行一个正整数 $m$,表示操作数。 +接下来 $m$ 行,每行表示一个操作。 + +## 输出格式 + +对于每一个询问操作,输出一行一个整数表示答案。 + +## 输入输出样例 #1 + +### 输入 #1 + +``` +3 +0 1 1 +1 2 2 +8 +SUM 0 2 +MAX 0 2 +N 0 1 +SUM 0 2 +MIN 0 2 +C 1 3 +SUM 0 2 +MAX 0 2 +``` + +### 输出 #1 + +``` +3 +2 +1 +-1 +5 +3 +``` + +## 说明/提示 + +【数据范围】 + +对于 $100\%$ 的数据,$1\le n,m \le 2\times 10^5$。 + +2020.02.04 修正了一点数据的错误 +2020.03.14 加入了一组 hack 数据 +2020.11.26 加入了一组 hack 数据 By @_Leaving \ No newline at end of file