1023 - 42个最短路? -The Shortest Statement (codeforces 1051F)

传送门

分析

好题,值得做一下
注意到m-n<=20这个条件
将原来的m条边看做(n-1)条树边,(m-n+1)条非树边
对于树边直接lca求距离。
由于非树边最多21条。
因此我们对这21条边连接的42个点都跑一次最短路来更新答案的最小值即可。
注意离散化,虽然点只有42个,但点的编号可能很大
注意数据范围,long long 类型的INF要开大一些,一般的调试方法,将题目中给出的小样例,调大其权值

代码

#include
#define in read()
#define N 100009
#define ll long long
#define inf (1ll<<50)
using namespace std;
inline int read(){
	int ans=0;
	char ch=getchar();
	while(!isdigit(ch))ch=getchar();
	while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch^48),ch=getchar();
	return ans;
}
int n,m;
int nxt[N<<1],head[N],cnt=1;
int fa[N][25],dep[N];
ll d[50][N],dtree[N];
int key[N<<1],num=0;
bool is_tree[N<<1],vis[N];
struct egde{
	int u,v;
	ll w;
}E[N<<1];
void add(int x,int y,int z){
	nxt[++cnt]=head[x];head[x]=cnt;E[cnt].v=y;E[cnt].w=z;E[cnt].u=x;
	nxt[++cnt]=head[y];head[y]=cnt;E[cnt].v=x;E[cnt].w=z;E[cnt].u=y;
}
void dfs1(int u,int fu){
	fa[u][0]=fu;dep[u]=dep[fu]+1;
	for(int e=head[u];e;e=nxt[e]){
		int v=E[e].v;
		if(v==fu||fa[v][0]) continue;
		is_tree[e]=is_tree[e^1]=1;
		dtree[v]=dtree[u]+E[e].w;
		dfs1(v,u);
	}
}
void spfa(int S){
	queue<int > q;
	int s=key[S];
	d[S][s]=0;q.push(s);
	while(!q.empty()){
		int u=q.front();q.pop();vis[u]=0;
		for(int e=head[u];e;e=nxt[e]){
			int v=E[e].v;
			if(d[S][v]>d[S][u]+E[e].w){
				d[S][v]=d[S][u]+E[e].w;
				if(!vis[v]){
					q.push(v);
					vis[v]=1;
				}
			}
		}
	}
}
int getlca(int x,int y){
	if(dep[x]<dep[y]) swap(x,y);
	int i;
	for(i=20;i>=0;--i) if(dep[fa[x][i]]>=dep[y]) x=fa[x][i];
	if(x==y) return x;
	for(i=20;i>=0;--i)
		if(fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
	return fa[x][0];
}
int main(){
	n=in;m=in;
	int i,j,k,u,v,w;
	for(int i=1;i<=44;++i) 
		for(int j=1;j<=n;++j) d[i][j]=inf;
	for(i=1;i<=m;++i){
		u=in;v=in;w=in;
		add(u,v,w);
	}
	dfs1(1,n+1);
	for(i=2;i<=cnt;i+=2)
		if(!is_tree[i])
			key[++num]=E[i].u,key[++num]=E[i].v;
	sort(key+1,key+num+1);
	int numm=unique(key+1,key+num+1)-key-1;
	for(i=1;i<=numm;++i){
		spfa(i);
	}
	for(j=1;j<=20;++j)
		for(i=1;i<=n;++i)
			fa[i][j]=fa[fa[i][j-1]][j-1];
	int q;
	q=in;
	for(i=1;i<=q;++i){
		u=in;v=in;
		int lca=getlca(u,v);
		ll ans=dtree[u]+dtree[v]-2*dtree[lca];
		for(j=1;j<=numm;++j){
			ans=min(ans,d[j][u]+d[j][v]);
		}
		cout<<ans<<'\n';
	}
	return 0;
}

你可能感兴趣的:(SPFA)