Description
给定一张简单无向连通图,要求支持两种操作:
-
修改一个点的点权。
-
询问两点之间所有简单路径上点权的最小值。
n , m , q ≤ 1 0 5 n,m,q \leq 10^5 n,m,q≤105
Solution
先不考虑修改。
圆方树有一个性质,那就是 ( u , v ) (u,v) (u,v)路径上的方点所代表的点双并为 ( u , v ) (u,v) (u,v)间的简单路径并。
所以只需要把方点权值设为其代表的点双中的最小值即可。
考虑修改,可以发现若直接套用上述做法,由于每个圆点连接的方点数为 O ( n ) O(n) O(n)的,所以复杂度会退化为 O ( n 2 ) O(n^2) O(n2)。
考虑一个常用的套路,那就是把每个方点的权值设为它子节点的权值最小值,每次修改时只用修改父节点即可,用堆维护。
注意当 l c a lca lca为方点时,要用其父节点权值更新答案。
#include <bits/stdc++.h>
using namespace std;
inline int gi()
{
char c = getchar();
while (c < '0' || c > '9') c = getchar();
int sum = 0;
while ('0' <= c && c <= '9') sum = sum * 10 + c - 48, c = getchar();
return sum;
}
inline char gc()
{
char c = getchar();
while (c < 'A' || c > 'Z') c = getchar();
return c;
}
const int maxn = 100005;
int n, m, q, w[maxn << 1];
struct edge
{
int to, next;
} e[maxn << 1];
int h[maxn], tot;
inline void add(int u, int v)
{
e[++tot] = (edge) {v, h[u]}; h[u] = tot;
e[++tot] = (edge) {u, h[v]}; h[v] = tot;
}
vector<int> to[maxn << 1];
int cnt, dep[maxn << 1], siz[maxn << 1], son[maxn << 1], ord[maxn << 1], dfn[maxn << 1], low[maxn << 1], Time, fa[maxn << 1], top[maxn << 1];
struct
{
priority_queue<int, vector<int>, greater<int> > q1, q2;
int Top()
{
while (!q2.empty() && q1.top() == q2.top()) q1.pop(), q2.pop();
return q1.top();
}
void insert(int x) {q1.push(x);}
void erase(int x) {q2.push(x);}
} val[maxn];
void dfs1(int u)
{
dep[u] = dep[fa[u]] + 1; siz[u] = 1;
for (int v : to[u])
if (v != fa[u]) {
fa[v] = u; dfs1(v);
siz[u] += siz[v];
if (siz[v] > siz[son[u]]) son[u] = v;
if (u > n) val[u - n].insert(w[v]);
}
if (u > n) w[u] = val[u - n].Top();
}
void dfs2(int u)
{
ord[dfn[u] = ++Time] = u;
if (son[u]) top[son[u]] = top[u], dfs2(son[u]);
else low[top[u]] = Time;
for (int v : to[u])
if (v != fa[u] && v != son[u]) top[v] = v, dfs2(v);
}
int rt[maxn << 1], Min[maxn << 3], lch[maxn << 3], rch[maxn << 3];
#define mid ((l + r) >> 1)
void build(int &s, int l, int r)
{
s = ++tot;
if (s > 2e5 * 4) puts("fuck you"), exit(0);
if (l == r) return Min[s] = w[ord[l]], void();
build(lch[s], l, mid);
build(rch[s], mid + 1, r);
Min[s] = min(Min[lch[s]], Min[rch[s]]);
}
void modify(int &s, int l, int r, int p)
{
if (l == r) return Min[s] = w[ord[l]], void();
if (p <= mid) modify(lch[s], l, mid, p);
else modify(rch[s], mid + 1, r, p);
Min[s] = min(Min[lch[s]], Min[rch[s]]);
}
int query(int s, int l, int r, int ql, int qr)
{
if (ql <= l && r <= qr) return Min[s];
if (qr <= mid) return query(lch[s], l, mid, ql, qr);
else if (ql > mid) return query(rch[s], mid + 1, r, ql, qr);
else return min(query(lch[s], l, mid, ql, qr), query(rch[s], mid + 1, r, ql, qr));
}
void modify(int v, int u)
{
if (fa[u]) val[fa[u] - n].erase(w[u]), val[fa[u] - n].insert(v), w[fa[u]] = val[fa[u] - n].Top();
w[u] = v;
modify(rt[top[u]], dfn[top[u]], low[top[u]], dfn[u]);
if (fa[u]) u = fa[u], modify(rt[top[u]], dfn[top[u]], low[top[u]], dfn[u]);
}
int query(int u, int v)
{
int ans = 1e9;
while (top[u] != top[v]) {
if (dep[top[u]] > dep[top[v]]) ans = min(ans, query(rt[top[u]], dfn[top[u]], low[top[u]], dfn[top[u]], dfn[u])), u = fa[top[u]];
else ans = min(ans, query(rt[top[v]], dfn[top[v]], low[top[v]], dfn[top[v]], dfn[v])), v = fa[top[v]];
}
if (dfn[u] > dfn[v]) swap(u, v);
ans = min(ans, query(rt[top[v]], dfn[top[v]], low[top[v]], dfn[u], dfn[v]));
if (u > n) ans = min(ans, w[fa[u]]);
return ans;
}
namespace Tarjan
{
int dfn[maxn], low[maxn], Time, stk[maxn], top;
void dfs(int u)
{
dfn[u] = low[u] = ++Time;
stk[++top] = u;
for (int i = h[u], v; v = e[i].to, i; i = e[i].next)
if (!dfn[v]) {
dfs(v);
low[u] = min(low[u], low[v]);
if (dfn[u] == low[v]) {
++cnt;
while (stk[top + 1] != v)
to[stk[top]].push_back(cnt), to[cnt].push_back(stk[top]), --top;
to[u].push_back(cnt), to[cnt].push_back(u);
}
} else low[u] = min(low[u], dfn[v]);
}
}
int main()
{
n = gi(); m = gi(); q = gi();
for (int i = 1; i <= n; ++i) w[i] = gi();
for (int i = 1; i <= m; ++i) add(gi(), gi());
cnt = n;
for (int i = 1; i <= n; ++i)
if (!Tarjan::dfn[i]) Tarjan::dfs(i);
for (int i = 1; i <= cnt; ++i)
if (!fa[i]) dfs1(i);
Time = 0;
for (int i = 1; i <= cnt; ++i)
if (!top[i]) top[i] = i, dfs2(i);
tot = 0;
for (int i = 1; i <= cnt; ++i)
if (top[i] == i) build(rt[i], dfn[i], low[i]);
for (int i = 1; i <= q; ++i) {
char c = gc();
if (c == 'C') modify(gi(), gi());
else printf("%d\n", query(gi(), gi()));
}
return 0;
}