建圆方树再树链剖分,线段树单点修改区间求 min,应该没哪里错吧,怎么回事呢?
#include <bits/stdc++.h>
using namespace std;
using LL = __int128; // 缺省源,可以忽略
using ll = long long;
using ldb = long double;
using vi = vector < int >;
#define ve vector < edge >
#define pb(x) emplace_back(x)
#define lowbit(x) ((x) & -(x))
#define me(a, b) memset(a, b, sizeof(a));
#define L(i, j, k) for (int i = j; i <= (k); i++)
#define R(i, j, k) for (int i = j; i >= (k); i--)
#define debug cerr << __FILE__ << ": " << __LINE__ << '\n';
#define qio() ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
namespace io { // 快读模板,可以忽略
char buf[1 << 21], *p1 = buf, *p2 = buf;
#define gc() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++)
int read() {
int res(0), f(1);
char ch(getchar());
while (ch < '0' || ch > '9') {
if (ch == '-')
f = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
res = res * 10 + (ch ^ '0');
ch = getchar();
}
return res * f;
}
} using io::read;
template < class T >
ostream& operator << (ostream& out, vector < T > v) {
out << '[';
if (!v.empty()) {
L(i, 0, v.size() - 2)
out << v[i] << ',';
out << v[v.size() - 1];
}
return out << ']';
}
namespace Dbg { // 用来 Debug 的部分,可以忽略
template < class T >
void dbg(char *f, T t) {
cerr << f << '=' << t << endl;
}
template < class T, class ...Ar >
void dbg(char *f, T x, Ar... y) {
while (*f != ',')
cerr << *f++;
cerr << '=' << x << ',';
dbg(f + 1, y...);
}
}
#define gdb(...) cerr << "gdb in line " <<__LINE__ << ": ", Dbg::dbg((char*)#__VA_ARGS__,__VA_ARGS__);
const int N = 1e5 + 5; // Adjust
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3fll;
int n, m, q, w[N];
vi G[N], T[N << 1];
multiset < int > bw[N];
namespace trjn {
int dfn[N], low[N], dfc, cnt;
int stk[N], top;
void rebuild(int u) { // 建圆方树
dfn[u] = low[u] = ++dfc;
stk[++top] = u;
for (int v : G[u])
if (!dfn[v]) {
rebuild(v);
low[u] = min(low[u], low[v]);
if (low[v] == dfn[u]) {
++cnt;
for (int x = 0; x != v; --top) {
T[x = stk[top]].pb(cnt);
T[cnt].pb(x);
}
T[cnt].pb(u);
T[u].pb(cnt);
}
} else
low[u] = min(low[u], dfn[v]);
}
}
namespace hld {
int fa[N << 1], dep[N << 1], siz[N << 1], hs[N << 1], top[N << 1], dfn[N << 1];
// Don't forget to time 2!
int dfc;
void dfs1(int u, int f) { // 剖
fa[u] = f;
dep[u] = dep[f] + 1;
siz[u] = 1;
for (int v : T[u])
if (v != f) {
dfs1(v, u);
if (siz[v] > siz[hs[u]])
hs[u] = v;
}
}
void dfs2(int u, int t) {
dfn[u] = ++dfc;
top[u] = t;
if (!hs[u])
return;
dfs2(hs[u], t);
for (int v : T[u])
if (v != fa[u] && v != hs[u])
dfs2(v, v);
}
struct sgt { // 树剖的线段树
int dt[N << 3];
sgt() {
me(dt, 0x3f);
}
#define ls(u) (u << 1)
#define rs(u) (u << 1 | 1)
#define pushup(u) dt[u] = min(dt[ls(u)], dt[rs(u)])
void modify(int s, int t, int k, int u, int d) {
// gdb(s, t, k, u, d);
if (s == t) {
dt[u] = d;
return;
}
int mid = (s + t) >> 1;
if (mid >= k)
modify(s, mid, k, ls(u), d);
else
modify(mid + 1, t, k, rs(u), d);
pushup(u);
}
int query(int s, int t, int l, int r, int u) {
if (l <= s && t <= r)
return dt[u];
int mid = (s + t) >> 1, res = inf;
if (mid >= l)
res = query(s, mid, l, r, ls(u));
if (mid < r)
res = min(res, query(mid + 1, t, l, r, rs(u)));
return res;
}
} tr;
void init() {
L(i, 2, n)
bw[fa[i] - n].insert(w[i]);
L(i, 1, n)
tr.modify(1, dfc, dfn[i], 1, w[i]);
L(i, n + 1, dfc)
tr.modify(1, dfc, dfn[i], 1, *bw[i - n].begin());
}
void modify(int u, int nw) {
if (!fa[u]) { // root 的特判,不给 ta 改父亲(fa[1] = 0)
tr.modify(1, dfc, dfn[u], 1, w[u] = nw);
return;
}
bw[fa[u] - n].erase(w[u]);
bw[fa[u] - n].insert(w[u] = nw);
tr.modify(1, dfc, dfn[u], 1, nw);
tr.modify(1, dfc, dfn[fa[u]], 1, *bw[fa[u] - n].begin());
}
int query(int u, int v) {
int res = inf;
while (top[u] != top[v]) {
if (dep[top[u]] < dep[top[v]])
swap(u, v);
res = min(res, tr.query(1, dfc, dfn[top[u]], dfn[u], 1));
// gdb(dfn[u], dfn[top[u]], res);
u = fa[top[u]];
}
if (dep[u] > dep[v])
swap(u, v);
res = min(res, tr.query(1, dfc, dfn[u], dfn[v], 1));
if (u > n) // u is a block vertex
res = min(res, w[fa[u]]);
return res;
}
}
int main() {
qio();
cin >> n >> m >> q;
trjn::cnt = n;
L(i, 1, n)
cin >> w[i];
int u, v;
while (m--) {
cin >> u >> v;
G[u].pb(v), G[v].pb(u);
}
trjn::rebuild(1); // 建圆方树
hld::dep[1] = 1; // 树剖
hld::dfs1(1, 0);
hld::dfs2(1, 1);
hld::init(); // 预处理树剖的线段树与 multiset
char opt;
while (q--) {
cin >> opt >> u >> v;
if (opt == 'A') {
printf("%d\n", hld::query(u, v));
} else {
hld::modify(u, v);
}
}
return 0;
}