题目大意:给定一张图(保证连通),每个点有点权。现在有两种操作:
1. $C;a;w:$把$a$的点权改为$w$;
2. $A;a;b:$询问从$a$到$b$的所有简单路径(不经过重复点)中,点权最小的点的点权。
题解:可以发现如果是一棵树,直接用树链剖分维护最值即可。
但是它是一个图,所以可以想到缩点。
题目要求不经过重复点,发现对于一个点双连通分量,如果到了其中的任意一个点,一定可以走到其中的点权最小的点。
于是想到把图中的点双缩点,维护圆方树,把方点的值设为它周围的圆点中点权最小的点的点权,树连剖分。
但是这样做有一个问题,每次修改一个圆点,都要修改周围的所有方点,如果一个点在多个点双中,每次修改的时间复杂度可以达到$nlog_2 n$级别,就会$TLE$
怎么办呢?
这时我们改变一下方点的值,可以把方点中的值改为它的儿子中最小值(而不是周围,也就是说,它的父亲的值不会影响这个方点)
看起来没什么是吧?
但是这样我们可以用$multiset$(**不是set**)来存它的每个儿子的值,修改一个圆点时,我们只修改这个圆点本身和这个点的父亲(也就是一个方点)的信息(注意如果修改的点是根就不修改父亲)。
修改复杂度$O(log_2 n)$(有可能是假的,我并不怎么会推)
询问时,像原来一样树链剖分,注意如果最后的节点是一个方点(也就是说查询的两个点的$LCA$是方点),那么这个方点的父亲就没有统计到答案中,但是它是有贡献的,于是要计算
时间复杂度$(O(nlog_2^2 n)$。
卡点:1.不会$tarjan$求点双
2.暴力修改$TLE$
C++ Code:
#include <cstdio> #include <set> #define maxn 100010 #define maxm 100010 #define N 200010 #define M 200010 using namespace std; const int inf = 0x7fffffff; inline int min(int a, int b) {return a < b ? a : b;} inline void swap(int &a, int &b) {a ^= b ^= a ^= b;} int n, m, q, cnt; int w[N]; struct Edge {int to, nxt;}; multiset <int> SM[N]; struct ST { int V[N << 1], W[N]; void build(int rt, int l, int r) { if (l == r) { V[rt] = W[l]; return ; } int mid = l + r >> 1; build(rt << 1, l, mid); build(rt << 1 | 1, mid + 1, r); V[rt] = min(V[rt << 1], V[rt << 1 | 1]); } void add(int rt, int l, int r, int x, int num) { if (l == r) { V[rt] = num; return ; } int mid = l + r >> 1; if (x <= mid) add(rt << 1, l, mid, x, num); else add(rt << 1 | 1, mid + 1, r, x, num); V[rt] = min(V[rt << 1], V[rt << 1 | 1]); } int ask(int rt, int l, int r, int L, int R) { if (L <= l && R >= r) { return V[rt]; } int mid = l + r >> 1, ans = inf; if (L <= mid) ans = ask(rt << 1, l, mid, L, R); if (R > mid) ans = min(ans, ask(rt << 1 | 1, mid + 1, r, L, R)); return ans; } } S; struct Tree { int head[N], cntE; Edge e[M << 1]; void addE(int a, int b) { e[++cntE] = (Edge) {b, head[a]}; head[a] = cntE; } int idx; int fa[N], dep[N], dfn[N], son[N], sz[N], top[N]; void dfs1(int rt) { sz[rt] = 1; son[rt] = 0; for (int i = head[rt]; i; i = e[i].nxt) { int v = e[i].to; if (!dep[v]) { dep[v] = dep[rt] + 1; fa[v] = rt; dfs1(v); sz[rt] += sz[v]; if (!son[rt] || sz[v] > sz[son[rt]]) son[rt] = v; } } } void dfs2(int rt) { dfn[rt] = ++idx; int v = son[rt]; if (v) top[v] = top[rt], dfs2(v); for (int i = head[rt]; i; i = e[i].nxt) { v = e[i].to; if (v != fa[rt] && v != son[rt]) { top[v] = v; dfs2(v); } } } void init(int rt) { int v; fa[rt] = idx = 0; dep[top[rt] = rt] = 1; dfs1(rt); dfs2(rt); for (int i = 1; i <= n; i++) S.W[dfn[i]] = w[i]; for (int i = n + 1; i <= cnt; i++) { for (int j = head[i]; j; j = e[j].nxt) { v = e[j].to; if (v != fa[i]) SM[i].insert(w[v]); } if (SM[i].empty()) w[i] = inf; else w[i] = *SM[i].begin(); S.W[dfn[i]] = w[i]; } S.build(1, 1, cnt); } void add(int x, int num) { int f = fa[x]; if (f) { SM[f].erase(SM[f].find(w[x])); SM[f].insert(num); w[f] = *SM[f].begin(); S.add(1, 1, cnt, dfn[f], w[f]); } w[x] = num; S.add(1, 1, cnt, dfn[x], num); } int ask(int x, int y) { int res = inf; while (top[x] != top[y]) { if (dep[top[x]] < dep[top[y]]) swap(x, y); res = min(res, S.ask(1, 1, cnt, dfn[top[x]], dfn[x])); x = fa[top[x]]; } if (dep[x] > dep[y]) swap(x, y); res = min(res, S.ask(1, 1, cnt, dfn[x], dfn[y])); if (x > n) res = min(res, w[fa[x]]); return res; } } T; struct Graph { int head[maxn], cntE; Edge e[maxm << 1]; int stack[maxn], DFN[maxn], low[maxn]; int idx, tot; bool vis[maxn]; void addE(int a, int b) { e[++cntE] = (Edge) {b, head[a]}; head[a] = cntE; } void tarjan(int rt) { vis[stack[++tot] = rt] = true; low[rt] = DFN[rt] = ++idx; int v, tmp; for (int i = head[rt]; i; i = e[i].nxt) { v = e[i].to; if (!DFN[v]) { tarjan(v); low[rt] = min(low[rt], low[v]); if (low[v] >= DFN[rt]) { cnt++; w[cnt] = inf; T.addE(cnt, rt); T.addE(rt, cnt); w[cnt] = min(w[cnt], w[rt]); do { vis[tmp = stack[tot--]] = false; T.addE(cnt, tmp); T.addE(tmp, cnt); } while(tmp != v); } } else { low[rt] = min(low[rt], DFN[v]); } } } } G; int main() { scanf("%d%d%d", &n, &m, &q); for (int i = 1; i <= n; i++) scanf("%d", &w[i]); for (int i = 1; i <= m; i++) { int a, b; scanf("%d%d", &a, &b); G.addE(a, b); G.addE(b, a); } cnt = n; G.tarjan(1); T.init(1); while (q--) { char op; int x, y; scanf("%s%d%d", op, &x, &y); if (op[0] == 'C') { T.add(x, y); } else { printf("%d ", T.ask(x, y)); } } return 0; }