Codeforces 1706E. Qpwoeirut and Vertices
\(\texttt{Difficulty:2300}\)
题目大意
思路
即求若干点两两之间路径上最大边权的最小值,显然 \(\texttt{Kruskal}\) 重构树即可解决,询问点的区间为 \([l,r]\) , 答案即为 \([l,r]\) 所有点在重构树上的 \(lca\) 的点权,\([l,r]\) 所有点的 \(lca\)为 \(lca(dfn最小的,dfn最大的)\) ,随遍一种快速查询区间 \(min,max\) 的方法即可,复杂度 \(O(nlogn)\) 。
代码
#include<bits/stdc++.h>
#include<unordered_map>
#include<unordered_set>
using namespace std;
using LL = long long;
using LD = long double;
using ULL = unsigned long long;
using PII = pair<LL, LL>;
using TP = tuple<int, int, int>;
#define all(x) x.begin(),x.end()
#define mst(x,v) memset(x,v,sizeof(x))
#define mk make_pair
//#define int LL
#define double LD
//#define lc p*2
//#define rc p*2+1
#define endl '\n'
#define inf 0x3f3f3f3f
#define INF 0x3f3f3f3f3f3f3f3f
#pragma warning(disable : 4996)
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
const double eps = 1e-8;
const double pi = acos(-1);
const LL MOD = 1000000007;
const LL mod = 998244353;
const int maxn = 300010;
int T, N, M, Q;
struct Edge {
int u, v, cost;
};
bool cmp(Edge& e1, Edge& e2)
{
return e1.cost < e2.cost;
}
int par[maxn], rk[maxn];
void init(int n)
{
for (int i = 1; i <= n; i++)
{
par[i] = i;
rk[i] = 0;
}
}
int find(int x)
{
if (x == par[x])
return x;
return par[x] = find(par[x]);
}
void unite(int x, int y)
{
x = find(x), y = find(y);
if (x == y)
return;
par[y] = x;
}
bool same(int x, int y)
{
return find(x) == find(y);
}
vector<int>G[maxn];
vector<Edge> es;
int val[maxn], cntv, cnte;
void add_edge(int from, int to)
{
G[from].push_back(to);
G[to].push_back(from);
}
void Kruskal()
{
sort(all(es), cmp), init(cntv);
for (auto& e : es)
{
int u = e.u, v = e.v;
if (!same(u, v))
{
int fu = find(u), fv = find(v);
cntv++;
par[cntv] = cntv, rk[cntv] = 0;
add_edge(fu, cntv), add_edge(cntv, fv);
unite(cntv, fu), unite(cntv, fv);
val[cntv] = e.cost;
}
if (cntv == N * 2 - 1)
break;
}
}
int fa[maxn], dep[maxn], siz[maxn], hson[maxn], top[maxn], dfn[maxn], rnk[maxn], tot;
void dfs1(int v, int p, int d)
{
fa[v] = p, dep[v] = d, siz[v] = 1;
for (auto& to : G[v])
{
if (to == p)
continue;
dfs1(to, v, d + 1);
siz[v] += siz[to];
if (!hson[v] || siz[to] > siz[hson[v]])
hson[v] = to;
}
}
void dfs2(int v, int p, int t)
{
dfn[v] = ++tot, rnk[tot] = v, top[v] = t;
if (!hson[v])
return;
dfs2(hson[v], v, t);
for (auto& to : G[v])
{
if (to == p || to == hson[v])
continue;
dfs2(to, v, to);
}
}
int STa[maxn][20], STb[maxn][20];
void MAX_init(int n)
{
for (int i = 0; i < n; i++)
STa[i][0] = dfn[i + 1];
for (int j = 1; (1 << j) <= n; j++)
{
for (int i = 0; i + (1 << j) - 1 < n; i++)
STa[i][j] = max(STa[i][j - 1], STa[i + (1 << (j - 1))][j - 1]);
}
}
void MIN_init(int n)
{
for (int i = 0; i < n; i++)
STb[i][0] = dfn[i + 1];
for (int j = 1; (1 << j) <= n; j++)
{
for (int i = 0; i + (1 << j) - 1 < n; i++)
STb[i][j] = min(STb[i][j - 1], STb[i + (1 << (j - 1))][j - 1]);
}
}
int MAX(int l, int r)//[l,r)
{
if (l >= r)
return 0;
int k = floor(log2(r - l));
return max(STa[l][k], STa[r - (1 << k)][k]);
}
int MIN(int l, int r)//[l,r)
{
if (l >= r)
return 0;
int k = floor(log2(r - l));
return min(STb[l][k], STb[r - (1 << k)][k]);
}
bool cmp2(int& a, int& b)
{
return dfn[a] < dfn[b];
}
int lca(int u, int v)
{
while (top[u] != top[v])
{
if (dep[top[u]] < dep[top[v]])
v = fa[top[v]];
else
u = fa[top[u]];
}
return dep[u] > dep[v] ? v : u;
}
void solve()
{
tot = 0;
Kruskal();
for (int i = 1; i <= cntv; i++)
hson[i] = 0;
dfs1(cntv, 0, 1), dfs2(cntv, 0, cntv);
MAX_init(cntv), MIN_init(cntv);
int l, r;
for (int i = 1; i <= Q; i++)
{
cin >> l >> r;
int num = 0, ans = 0, mi = MAX(l - 1, r), mx = MIN(l - 1, r);
ans = val[lca(rnk[mi], rnk[mx])];
cout << ans << ' ';
}
cout << endl;
}
int main()
{
IOS;
cin >> T;
while (T--)
{
int u, v;
es.clear();
cin >> N >> M >> Q;
for (int i = 1; i <= N + M; i++)
G[i].clear(), val[i] = 0;
cntv = N, cnte = M;
for (int i = 1; i <= M; i++)
cin >> u >> v, es.push_back(Edge{ u,v,i });
solve();
}
return 0;
}