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;
}
posted @ 2022-07-21 10:56  notyour_young  阅读(69)  评论(0编辑  收藏  举报