圆方树第二题……
图中询问的是指定两点之间简单路径上点的最小权值。若我们建出圆方树,圆点的权值为自身权值,方点的权值为所连接的圆点的权值最小值(即点双连通分量中的最小权值)。我们可以发现其实就是这两点在圆方树上经过的点的最小权值,因为在这上面若经过了一个方点,说明可以经过这个点双连通分量中任何一个点并且到达想到的点。(方点所连接的点都是相互可达的)。
所以问题转化为了求树上两点之间路径的最小点权。并且需要注意的是:链顶的点需要把它的父亲节点也考虑进来,因为它的父亲节点与它是属于同一个双连通分量的。感觉圆方树的好处在这里就可以体现出来:即可以通过一个点来反映出整个点双联通分量的情况,并且相连的方点圆点一定是父子关系,由此可以方便的在树上通过一条路径来总结出很多双联通分量的总情况。
所以:树剖+可修改堆可以完美解决。
#include <bits/stdc++.h> using namespace std; #define maxn 400000 #define int long long #define INF 99999999999 int n, m, Q, val[maxn]; int tot, timer, dfn[maxn], low[maxn]; int cnt, fa[maxn], top[maxn], dep[maxn]; int S[maxn], size[maxn], hson[maxn]; struct node { int minn; node () { minn = INF; } }P[maxn]; struct heap { priority_queue <int, vector<int>, greater<int> > q1, q2; void ins(int x) { q1.push(x); } void erase(int x) { q2.push(x); } int top() { while(!q2.empty() && q1.top() == q2.top()) q1.pop(), q2.pop(); return q1.top(); } }Hp[maxn]; struct edge { int cnp = 1, head[maxn], to[maxn], last[maxn]; void add(int u, int v) { to[cnp] = v, last[cnp] = head[u], head[u] = cnp ++; to[cnp] = u, last[cnp] = head[v], head[v] = cnp ++; } }E1, E2; int read() { int x = 0, k = 1; char c; c = getchar(); while(c < '0' || c > '9') { if(c == '-') k = -1; c = getchar(); } while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar(); return x * k; } void Tarjan(int u) { dfn[u] = low[u] = ++ timer; S[++ S[0]] = u; for(int i = E1.head[u]; i; i = E1.last[i]) { int v = E1.to[i]; if(!dfn[v]) { Tarjan(v); low[u] = min(low[u], low[v]); if(low[v] >= dfn[u]) { E2.add(++ tot, u); int x = 0; do { x = S[S[0] --]; E2.add(tot, x); }while(x != v); } } else low[u] = min(low[u], dfn[v]); } } void dfs(int u, int ff) { fa[u] = ff; dep[u] = dep[ff] + 1; size[u] = 1; if(u <= n && ff) Hp[ff].ins(val[u]); for(int i = E2.head[u]; i; i = E2.last[i]) { int v = E2.to[i]; if(v == ff) continue; dfs(v, u); size[u] += size[v]; if(size[v] > size[hson[u]]) hson[u] = v; } } void dfs2(int u, int gra) { dfn[u] = ++ timer; top[u] = gra; if(hson[u]) dfs2(hson[u], gra); for(int i = E2.head[u]; i; i = E2.last[i]) { int v = E2.to[i]; if(v == fa[u] || v == hson[u]) continue; dfs2(v, v); } } void update(int p, int l, int r, int x, int num) { if(l == r) { P[p].minn = num; return; } int mid = (l + r) >> 1; if(x <= mid) update(p << 1, l, mid, x, num); else update(p << 1 | 1, mid + 1, r, x, num); P[p].minn = min(P[p << 1].minn, P[p << 1 | 1].minn); } int query(int p, int l, int r, int L, int R) { if(l > R || r < L) return INF; if(l >= L && r <= R) return P[p].minn; int mid = (l + r) >> 1; return min(query(p << 1, l, mid, L, R), query(p << 1 | 1, mid + 1, r, L, R)); } signed main() { tot = n = read(), m = read(), Q = read(); for(int i = 1; i <= n; i ++) val[i] = read(); for(int i = 1; i <= m; i ++) { int u = read(), v = read(); E1.add(u, v); } for(int i = 1; i <= n; i ++) if(!dfn[i]) Tarjan(i); timer = 0; dfs(1, 0), dfs2(1, 1); for(int i = 1; i <= n; i ++) update(1, 1, tot, dfn[i], val[i]); for(int i = n + 1; i <= tot; i ++) update(1, 1, tot, dfn[i], Hp[i].top()); while(Q --) { char c; cin >> c; int a = read(), b = read(); if(c == 'C') { if(fa[a]) Hp[fa[a]].erase(val[a]); val[a] = b; update(1, 1, tot, dfn[a], val[a]); if(fa[a]) Hp[fa[a]].ins(val[a]), update(1, 1, tot, dfn[fa[a]], Hp[fa[a]].top()); } else { int u = a, v = b, ans = INF; while(top[u] != top[v]) { if(dep[top[u]] < dep[top[v]]) swap(u, v); ans = min(ans, query(1, 1, tot, dfn[top[u]], dfn[u])); u = fa[top[u]]; } if(dep[u] > dep[v]) swap(u, v); ans = min(ans, query(1, 1, tot, dfn[u], dfn[v])); if(u > n) ans = min(ans, val[fa[u]]); printf("%lld ", ans); } } return 0; }