Codeforces Round #809 (Div. 2) E. Qpwoeirut and Vertices (kruskal 重构树 + ST表/ 线段树 + lca)
E. Qpwoeirut and Vertices
题意 :给定一个联通的无向图,n个点,m条边,进行q次询问,每次询问给出 \(l\) 和 \(r\) ,回答,仅用编号前 \(k\) 条边,就可以使编号在 \(l\) 和 \(r\) 之间内的所有点联通的 \(k\) 的最小值
分析 :根据题目规定,我们定义给出边的编号即为这条边的权重,对于一堆点,求一个使得他们联通的边权最小值,考虑kruskal重构树,那么问题就转化为求 \([l,r]\) 中所有点的lca,lca的点权即为所求,对于一群点的lca,即为 \([l,r]\) dfs序最小的点,和dfs序最大的点的lca,这样做法就清楚了,先建出kruskal重构树,再预处理出每个点的时间戳,查询区间最值经典的RMQ问题,最后倍增求lca
ac代码
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <queue>
#include <map>
#include <vector>
#include <stack>
#include <set>
#include <sstream>
#include <fstream>
#include <cmath>
#include <iomanip>
#include <unordered_map>
#include <unordered_set>
#define x first
#define y second
#define ios ios::sync_with_stdio(false),cin.tie(0);
#define endl '\n'
#define pb push_back
#define all(x) x.begin(),x.end()
#define all1(x) x.begin()+1,x.end()
#define pi 3.14159265358979323846
using namespace std;
typedef long long LL;
typedef pair<int,int> PII;
const int N = 200010,M = 200010,INF = 0x3f3f3f3f,mod = 1e9 + 7;
const double INFF = 0x7f7f7f7f7f7f7f7f;
int n,m,k,t;
int h[N],e[M],ne[M],idx,v[N];
int p[N];
int dfn[N],timestamp;
int depth[N],fa[N][20];
int maxv[N][20],minv[N][20];
int ans[N];
struct Edge
{
int a,b,w;
bool operator < (const Edge & W)
{
return w < W.w;
}
}edges[M];
void add(int a, int b)
{
e[idx] = b,ne[idx] = h[a],h[a] = idx ++;
}
int find(int x)
{
if(x != p[x]) return p[x] = find(p[x]);
return x;
}
void dfs(int u,int f)
{
depth[u] = depth[f] + 1;
fa[u][0] = f;
for(int k = 1;k <= 18;k ++)
fa[u][k] = fa[fa[u][k - 1]][k - 1];
dfn[u] = ++ timestamp,ans[timestamp] = u;
for(int i = h[u];~ i;i = ne[i])
{
int j = e[i];
if(j == f) continue;
dfs(j,u);
}
}
int lca(int a,int b)
{
if(depth[a] < depth[b]) swap(a,b);
for(int k = 18;k >= 0;k --)
if(depth[fa[a][k]] >= depth[b])
{
a = fa[a][k];
}
if(a == b) return a;
for(int k = 18;k >= 0;k --)
if(fa[a][k] != fa[b][k])
{
a = fa[a][k];
b = fa[b][k];
}
return fa[a][0];
}
void maxv_init()
{
for(int j = 0;j <= 18;j ++)
for(int i = 1;i + (1 << j) - 1 <= n;i ++)
{
if(!j) maxv[i][j] = dfn[i];
else maxv[i][j] = max(maxv[i][j - 1],maxv[i + (1 << j - 1)][j - 1]);
}
}
int maxv_query(int l,int r)
{
int len = r - l + 1;
int k = log(len) / log(2);
return max(maxv[l][k],maxv[r - (1 << k) + 1][k]);
}
void minv_init()
{
for(int j = 0;j <= 18;j ++)
for(int i = 1;i + (1 << j) - 1 <= n;i ++)
{
if(!j) minv[i][j] = dfn[i];
else minv[i][j] = min(minv[i][j - 1],minv[i + (1 << j - 1)][j - 1]);
}
}
int minv_query(int l,int r)
{
int len = r - l + 1;
int k = log(len) / log(2);
return min(minv[l][k],minv[r - (1 << k) + 1][k]);
}
int main()
{
ios;
cin >> t;
while(t --)
{
cin >> n >> m >> k;
memset(h,-1,sizeof (int) * (n + n + 1));
memset(depth,0,sizeof (int) * (n + 1 + n));
idx = timestamp = 0;
for(int i = 1;i <= n + n;i ++)
{
memset(minv[i],0x3f,sizeof minv[i]);
memset(maxv[i],0,sizeof maxv[i]);
memset(fa[i],0,sizeof fa[i]);
}
for(int i = 1;i <= m;i ++)
{
int a,b;
cin >> a >> b ;
edges[i] = {a,b,i};
}
for(int i = 1;i <= n + n;i ++) p[i] = i;
sort(edges + 1,edges + 1 + m);
for(int i = 1;i <= m;i ++)
{
int a = edges[i].a,b = edges[i].b,w = edges[i].w;
a = find(a),b = find(b);
if(a != b)
{
p[a] = p[b] = ++ n;
v[n] = w;
add(n,a),add(n,b);
}
}
dfs(n,0);
minv_init();
maxv_init();
while(k --)
{
int l,r;
cin >> l >> r;
if(l == r) cout << 0 << ' ';
else
{
int a = minv_query(l,r);
int b = maxv_query(l,r);
a = ans[a],b = ans[b];
int anc = lca(a,b);
cout << v[anc] << ' ';
}
}
cout << endl;
}
return 0;
}