一道圆方树恶心题,*3200,不知道为什么不评黑。
这道题很容易直接想到圆方树:因为两个操作如果在树上,都需要树链剖分 + 线段树维护。而将这么一个普通图转化为一棵树,也就只有圆方树这种形式了。
于是就可以综合使用圆方树 + 线段树 + 树链剖分轻松解决了这道题,码长达到了 3.95KB,恐怖。
#include <bits/stdc++.h>
#define int long long
#define ls(x) (x<<1)
#define rs(x) (x<<1|1)
#define mid ((l+r)>>1)
using namespace std;
int n, m, q;
const int N = 200010, INF = 1e18;
int val[N], cnt;
multiset<int> st[N];
struct segment { //线段树
int seg[N * 4], w[N * 4];
void build(int now, int l, int r) {
if (l == r) {
seg[now] = w[l];
return ;
}
build(ls(now), l, mid);
build(rs(now), mid + 1, r);
seg[now] = min(seg[ls(now)], seg[rs(now)]);
}
int query(int now, int l, int r, int ql, int qr) {
if (l >= ql && r <= qr)
return seg[now];
int ans = 1e9;
if (ql <= mid)
ans = min(ans, query(ls(now), l, mid, ql, qr));
if (qr > mid)
ans = min(ans, query(rs(now), mid + 1, r, ql, qr));
return ans;
}
void update(int now, int l, int r, int pos, int val) {
if (l == r) {
seg[now] = val;
return ;
}
if (pos <= mid)
update(ls(now), l, mid, pos, val);
else
update(rs(now), mid + 1, r, pos, val);
seg[now] = min(seg[ls(now)], seg[rs(now)]);
}
} sk;
struct tree { //树链剖分
vector<int> v[N];
int fa[N], dep[N], son[N], siz[N];
int dfn[N], ind, top[N];
void add(int x, int y) {
v[x].push_back(y);
}
void dfs1(int u, int pre) {
siz[u] = 1;
son[u] = 0;
int mx = 0;
for (auto i : v[u]) {
if (dep[i] || i == pre)
continue;
dep[i] = dep[u] + 1;
fa[i] = u;
dfs1(i, u);
siz[u] += siz[i];
if (son[u] == 0 || siz[i] > mx)
mx = siz[i], son[u] = i;
}
}
void dfs2(int u, int tp) {
top[u] = tp;
dfn[u] = ++ind;
if (son[u] == 0)
return ;
dfs2(son[u], tp);
for (auto i : v[u]) {
if (i == son[u] || i == fa[u])
continue;
dfs2(i, i);
}
}
void init() {
dep[1] = top[1] = 1;
fa[1] = ind = 0;
dfs1(1, 0);
// cout << "I AK IOI!";
dfs2(1, 1);
for (int i = 1; i <= n; i++)
sk.w[dfn[i]] = val[i];
for (int i = n + 1; i <= cnt; i++) {
for (auto j : v[i])
if (j != fa[i])
st[i].insert(val[j]);
if (st[i].empty())
val[i] = INF;
else
val[i] = *st[i].begin();
sk.w[dfn[i]] = val[i];
}
sk.build(1, 1, cnt);
}
void modify(int x, int y) {
if (fa[x] > 0) {
st[fa[x]].erase(st[fa[x]].find(val[x]));
st[fa[x]].insert(y);
val[fa[x]] = *st[fa[x]].begin();
sk.update(1, 1, cnt, dfn[fa[x]], val[fa[x]]);
}
val[x] = y;
sk.update(1, 1, cnt, dfn[x], y);
}
int query(int x, int y) {
int ret = INF;
while (top[x] != top[y]) {
// cout << x << " " << y << endl;
if (dep[top[x]] < dep[top[y]])
swap(x, y);
ret = min(ret, sk.query(1, 1, cnt, dfn[top[x]], dfn[x]));
x = fa[top[x]];
}
ret = min(ret, sk.query(1, 1, cnt, min(dfn[x], dfn[y]), max(dfn[x], dfn[y])));
if (x > n)
ret = min(ret, val[fa[x]]);
return ret;
}
} t;
struct tarj {
int low[N], dfn[N];
int ind = 0;
vector<int> v[N];
stack<int> stk;
void add(int x, int y) {
v[x].push_back(y);
}
void tarjan(int u, int pre) {
low[u] = dfn[u] = ++ind;
stk.push(u);
// cout << u << endl;
for (auto i : v[u]) {
// cout << i << " ";
if (i == pre)
continue;
if (!dfn[i]) {
tarjan(i, u);
low[u] = min(low[u], low[i]);
if (low[i] >= dfn[u]) {
cnt++;
val[cnt] = INF;
t.add(u, cnt);
t.add(cnt, u);
val[cnt] = min(val[cnt], val[u]);
int x;
do {
x = stk.top();
if (x == u)
break;
stk.pop();
t.add(cnt, x);
t.add(x, cnt);
} while (x != i && !stk.empty());
}
} else
low[u] = min(low[u], dfn[i]);
}
// cout << endl;
}
} tj;
signed main() {
cin >> n >> m >> q;
cnt = n;
for (int i = 1; i <= n; i++)
cin >> val[i];
for (int i = 1; i <= m; i++) {
int x, y;
cin >> x >> y;
tj.add(x, y);
tj.add(y, x);
}
tj.tarjan(1, 0);
t.init();
while (q--) {
char c;
cin >> c;
int x, y;
cin >> x >> y;
if (c == 'C')
t.modify(x, y);
else
cout << t.query(x, y) << endl;
}
return 0;
}