Blog of RuSun

\begin {array}{c} \mathfrak {One Problem Is Difficult} \\\\ \mathfrak {Because You Don't Know} \\\\ \mathfrak {Why It Is Diffucult} \end {array}

CF487E Tourists

LuoGu: CF487E Tourists

CF: E. Tourists

建出圆方树,对于方点,用 multiset 维护出子树内最小的值,求两点之间点权的最小值可以用树链剖分。(注意如果LCA是圆点,那么其父亲是方点,包含这个点双的信息,也要考虑)

查看代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
#include <cstdio>
#include <set>
#include <vector>
#define pb push_back
using namespace std;
template <class Type>
void read (Type &x)
{
char c;
bool flag = false;
while ((c = getchar()) < '0' || c > '9')
c == '-' && (flag = true);
x = c - '0';
while ((c = getchar()) >= '0' && c <= '9')
x = (x << 1) + (x << 3) + c - '0';
flag && (x = ~x + 1);
}
template <class Type, class ...rest>
void read (Type &x, rest &...y) { read(x), read(y...); }
template <class Type>
void write (Type x)
{
x < 0 && (putchar('-'), x = ~x + 1);
x > 9 && (write(x / 10), 0);
putchar('0' + x % 10);
}
typedef long long LL;
const int N = 2e5 + 10, inf = 1e9;
int top, stk[N];
int stmp, dfn[N], low[N];
int n, m, q, tot, p[N], w[N];
multiset <int> s[N];
vector <int> g[N], e[N];
namespace TreeSplit
{
int mn[N << 2];
int d[N], sz[N], son[N];
int stmp, top[N], dfn[N], rnk[N];
void dfs1 (int u = 1)
{
sz[u] = 1;
for (int v : e[u]) if (v ^ p[u])
{
p[v] = u;
d[v] = d[u] + 1;
dfs1(v);
sz[u] += sz[v];
if (sz[v] > sz[son[u]]) son[u] = v;
}
}
void dfs2 (int u = 1, int t = 1)
{
rnk[dfn[u] = ++stmp] = u;
top[u] = t;
if (!son[u]) return;
dfs2(son[u], t);
for (int v : e[u])
if (v ^ p[u] && v ^ son[u]) dfs2(v, v);
}
void pushup (int x) { mn[x] = min(mn[x << 1], mn[x << 1 | 1]); }
void build (int L = 1, int R = tot, int x = 1)
{
if (L == R) return void(mn[x] = w[rnk[L]]);
int mid = L + R >> 1;
build(L, mid, x << 1), build(mid + 1, R, x << 1 | 1);
pushup(x);
}
void modify (int t, int k, int L = 1, int R = tot, int x = 1)
{
if (L == R) return void(mn[x] = k);
int mid = L + R >> 1;
t <= mid ? modify(t, k, L, mid, x << 1) : modify(t, k, mid + 1, R, x << 1 | 1);
pushup(x);
}
int query (int l, int r, int L = 1, int R = tot, int x = 1)
{
if (l > R || L > r) return inf;
if (L >= l && R <= r) return mn[x];
int mid = L + R >> 1;
return min(query(l, r, L, mid, x << 1), query(l, r, mid + 1, R, x << 1 | 1));
}
int QueryPath (int a, int b)
{
int res = inf;
while (top[a] ^ top[b])
{
if (d[top[a]] < d[top[b]]) swap(a, b);
res = min(res, query(dfn[top[a]], dfn[a]));
a = p[top[a]];
}
if (d[a] > d[b]) swap(a, b);
res = min(res, query(dfn[a], dfn[b]));
if (a > n) res = min(res, w[p[a]]);
return res;
}
}
void tarjan (int u)
{
stk[++top] = u;
low[u] = dfn[u] = ++stmp;
for (int v : g[u])
if (!dfn[v])
{
tarjan(v);
low[u] = min(low[u], low[v]);
if (low[v] == dfn[u])
{
w[++tot] = 0;
int x;
do
{
x = stk[top--];
e[tot].pb(x), e[x].pb(tot);
++w[tot];
} while (x ^ v);
e[tot].pb(u), e[u].pb(tot), ++w[tot];
}
}
else low[u] = min(low[u], dfn[v]);
}
int main ()
{
read(n, m, q);
for (int i = 1; i <= n; ++i) read(w[i]);
for (int a, b; m; --m)
read(a, b), g[a].pb(b), g[b].pb(a);
tot = n;
tarjan(1);
TreeSplit::dfs1(), TreeSplit::dfs2();
for (int i = 1; i <= n; ++i)
if (p[i]) s[p[i]].insert(w[i]);
for (int i = n + 1; i <= tot; ++i)
w[i] = *s[i].begin();
TreeSplit::build();
for (char op[3]; q; --q)
{
scanf("%s", op);
if (*op == 'C')
{
int a, b; read(a, b);
TreeSplit::modify(TreeSplit::dfn[a], b);
if (p[a])
{
int c = p[a];
s[c].erase(w[a]), s[c].insert(b);
if (w[c] ^ *s[c].begin())
TreeSplit::modify(TreeSplit::dfn[c], w[c] = *s[c].begin());
}
w[a] = b;
}
else
{
int a, b; read(a, b);
write(TreeSplit::QueryPath(a, b)), puts("");
}
}
return 0;
}