[ABC287Ex] Directed Graph and Query 题解

题目传送门

思路

假设对于两个点 \(s_i,t_i\),在不考虑路径起点终点的情况下,最小的成本为 \(x\),那么只经过编号 \(1\sim x\) 的点一定能使 \(s_i,t_i\) 联通。所以问题就变成了求满足上述条件的最小的 \(x\)

有向图的连通性问题,很容易想到传递闭包。不会的出门左转

考虑传递闭包的过程,第一步就是枚举中转点。而如果我们从小到大枚举,刚好枚举了一个前缀,与上面的条件对应。

具体的做法也很简单,先离线。在做传递闭包的过程中,如果枚举中转点 \(k\) 之后 \(s_i,t_i\) 第一次联通,那么这个询问的答案就是 \(\max(s_i,t_i,k)\)

传递闭包采用 bitset 优化,时间复杂度 \(O(\frac {n^3}{\omega}+nq)\)

代码

#include <bits/stdc++.h>
using namespace std;

template<typename T> inline void read(T &x)
{
	x = 0;
	T f = 1;char ch = getchar();
	while(ch<'0'||ch>'9')
	{
		if(ch=='-')
		{
			f = -1,ch = getchar();
			break;
		}
		ch = getchar();
	}
	while(ch>='0'&&ch<='9')
		x = (x<<3)+(x<<1)+ch-48,ch = getchar();
	x*=f;
}
template<typename T> inline T read()
{
	T x;read(x);return x;
}
template<typename T> void write(T x)
{
    if(x<0) x = -x,putchar('-');
    if(x>9) write(x/10);
    putchar(x%10+48);
}
template<typename T> inline void writen(T x)
{
    write(x);
    putchar(10);
}
const int N = 2e3+5,M = 1e4+5;
int n,m,s[M],t[M],ans[M],q;
bitset<N> e[N];
signed main()
{
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
	read(n),read(m);
	for(int i = 1,u,v;i<=m;i++)
		read(u),read(v),e[u][v] = 1;
	read(q);
	for(int i = 1;i<=q;i++)
		read(s[i]),read(t[i]),ans[i] = -1;
	for(int k = 1;k<=n;k++)
	{
		for(int i = 1;i<=n;i++)
			if(e[i][k]) e[i]|=e[k];
		for(int i = 1;i<=q;i++)
			if(e[s[i]][t[i]]&&ans[i]==-1) ans[i] = max({s[i],t[i],k});
	}
	for(int i = 1;i<=q;i++)
		writen(ans[i]);
	return 0;
}
posted @ 2024-04-08 16:34  pyy1  阅读(18)  评论(0)    收藏  举报