P14912 海盗地图

Luogu 链接

题意

给定一个 \(n\) 个点 \(m\) 条边的无向连通图。
接下来你要回答 \(q\) 次询问,每次给定 \(u\)\(v\),询问 \(u\)\(v\) 的最短路。
保证最短路的长度严格大于 \(\sqrt{n}\)

保证 \(1\le n\le10^4,1\le m\le10^5,1\le q\le3\cdot10^4\)

思路

考虑 \(\text{Subtask}_3\) 的做法,可以发现需要选择一些点作为源点跑 \(\text{BFS}\)
若选取的点集为 \(S\),则时间复杂度为 \(O(|S|(n+m)+q)\)

考虑拓展这一做法。

发现若 \(u\)\(v\) 的最短路上存在点 \(s\) 属于 \(S\),则 \(\operatorname{dis}(u,v)=\operatorname{dis}(s,u)+\operatorname{dis}(s,v)\)

考虑一个具有一定错误率的做法。
我们选定一个点集 \(S\),以这些点为源点分别跑 \(\text{BFS}\)
询问时回答 \(\min\limits_{s\in S}\{\operatorname{dis}(s,u)+\operatorname{dis}(s,v)\}\)
时间复杂度为 \(O(|S|(n+m+q))\)

经过一定计算,该算法的正确率 \(P=(1-(1-\dfrac{\sqrt{n}}{n})^{|S|})^q\)
解得 \(|S|=\dfrac{\ln(1-P^{\frac{1}{q}})}{\ln(1-\frac{1}{\sqrt{n}})}\)

\(P=1-10^{-5}\),可以得到 \(|S|=2171\)
实测可以通过。

程序

AC 记录

#include<bits/stdc++.h>
#define forUp(i,a,b) for(int i=(a);i<=(b);++i)
#define forUP(i,a,b) for(int i=(a);i<(b);++i)
#define forDown(i,a,b) for(int i=(a);i>=(b);--i)
#define forG(u,v) for(int __i=head[u],v=to[__i];__i;__i=nxt[__i],v=to[__i])
#define forWG(u,v,c) for(int __i=head[u],v=to[__i],c=w[__i];__i;__i=nxt[__i],v=to[__i],c=w[__i])
#define pushb push_back
#define popb pop_back
#define pushf push_front
#define popf pop_front
#define popc __builtin_popcount
#define popc64 __builtin_popcountll
#define seteps(n) fixed<<setprecision((n))
bool __mst;using uint=unsigned int;using int64=long long;using uint64=unsigned long long;using int128=__int128;using uint128=unsigned __int128;using float64=double;using float80=long double;
constexpr int INF=0x3f3f3f3f,MINF=0xcfcfcfcf;constexpr int64 INF64=0x3f3f3f3f3f3f3f3f,MINF64=0xcfcfcfcfcfcfcfcf;constexpr float64 INFDB=1e50,eps=1e-8;
template<class _Tp>inline void chkMax(_Tp &x,const _Tp &y){if(x<y)x=y;}template<class _Tp>inline void chkMin(_Tp &x,const _Tp &y){if(x>y)x=y;}
inline int addMod(const int &x,const int &y,const int mod){int ans=x+y;return ans>=mod?ans-mod:ans;}inline int subMod(const int &x,const int &y,const int mod){int ans=x-y;return ans<0?ans+mod:ans;}
constexpr int N=1e4+10,S=2171;int __test_num=1,__task_id,__tst;using namespace std;void __init();

int n,m,q;vector<int> G[N];

int dis[S][N];
void bfs(int id,int s){
	queue<int> q;memset(dis[id],INF,sizeof(dis[id]));
	dis[id][s]=0,q.push(s);
	while(!q.empty()){
		int u=q.front();q.pop();
		for(int v:G[u])if(dis[id][u]+1<dis[id][v]){
			dis[id][v]=dis[id][u]+1;
			q.push(v);
		}
	}
}

bool __med;void __solve(int __test_id){
	cin>>n>>m>>q;
	while(m--){
		int u,v;cin>>u>>v;
		G[u].pushb(v);G[v].pushb(u);
	}
	vector<int> tmp(n);forUP(i,0,n)tmp[i]=i+1;
	mt19937 rnd(20081028u*20110626u);shuffle(tmp.begin(),tmp.end(),rnd);
	int lim=min(n,S);
	forUP(i,0,lim)bfs(i,tmp[i]);
	while(q--){
		int u,v,ans=INF;cin>>u>>v;
		forUP(i,0,lim)chkMin(ans,dis[i][u]+dis[i][v]);
		cout<<ans<<' ';
	}
}
signed main(){
	__init();
	forUp(i,1,__test_num)__solve(i);
	cerr<<1000.0*(clock()-__tst)/CLOCKS_PER_SEC<<"ms "<<((&__mst)-(&__med))/1024.0/1024.0<<"MB"<<'\n';
	return 0;
}
void __init(){
	__tst=clock();
	#ifndef use_file
	//#define use_file
	#endif
	#ifdef use_file
	const string __file_name="test";freopen((__file_name+".in").c_str(),"r",stdin);freopen((__file_name+".out").c_str(),"w",stdout);
	#endif
	ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
	//scanf("%d",&__test_num);
	//cin>>__test_num;
}
posted @ 2026-01-01 14:54  LXcjh4998  阅读(0)  评论(0)    收藏  举报