[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;
}

浙公网安备 33010602011771号