CF1051F The Shortest Statement

链接

CF1051F


比较好玩的一道题,居然是前几天模拟T2的部分且弱化版。

我会 Dijkstra!\(O(n^2)\)

我们一眼看到这个特殊条件 \(m-n\le 20\),显然这是说这张图应该看做一棵树上挂了 \(21\) 条特殊边。

我们随便找一棵树出来,然后可以把最短路分成两类,一类不经过特殊边,一类经过特殊边,不经过的我们可以直接在树上求出来,如果经过特殊边就可以注意到特殊边只有 \(21\) 条,然后连接特殊边的特殊点只有 \(42\) 个。我们考虑枚举经过特殊边的路径上第一个和最后一个特殊点,那么现在问题就转化为了特殊点之间的最短路,利用树上的距离和树上挂的边就可以跑一个floyd把特殊点两两最短路跑出来,然后这题就做完了。

然后一点注意的是最后枚举特殊点时先把每个特殊点到所有点的树上距离预处理出来,最后处理询问时时间复杂度可以从 \(1600n\log n\) 降到 \(1600n\)

然后把 \(n,m,q\) 看做同阶的话这题时间复杂度大概就是 \(O(n+n\alpha(n)+n\log n+40^3+40^2n)\) 吧。

code

点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define cs const
#define in read()
inline int read(){
	int p=0,f=1;
	char c=getchar();
	while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
	while(isdigit(c)){p=p*10+c-48;c=getchar();}
	return p*f;
}
cs int N=100005;
cs int M=45;
int n,m,q;
struct Graph{
	struct edge{
		int v,w,nxt;
	}e[N<<1];
	int head[N],en;
	void insert(int u,int v,int w)
		{e[++en].v=v,e[en].w=w,e[en].nxt=head[u],head[u]=en;}	
}T;
struct llmmkk{
	int u,v,w;
	bool operator<(const llmmkk &b)
		{return w>b.w;}
}E[N];
int fa[N];
inline int getf(int x){return fa[x]==x?x:fa[x]=getf(fa[x]);}
inline bool merge(int x,int y){
	int f1=getf(x),f2=getf(y);
	if(f1==f2)return false;
	fa[f2]=f1;return true;
}
int vip[M],pn;
inline int bin(int x){int l=1,r=pn,mid=(l+r)>>1;for(;l<r;mid=(l+r)>>1)if(vip[mid]<x)l=mid+1;else r=mid;return l;}
int f[20][N],dep[N],dis[N];
inline void dfs(int u,int far){
	f[0][u]=far,dep[u]=dep[far]+1;
	for(int i=1;i<=19;i++)
		f[i][u]=f[i-1][f[i-1][u]];
	for(int i=T.head[u],v=T.e[i].v,w=T.e[i].w;i;i=T.e[i].nxt,v=T.e[i].v,w=T.e[i].w)
		if(v^far)dis[v]=dis[u]+w,dfs(v,u);
}
inline int lca(int x,int y){
	if(dep[x]<dep[y])swap(x,y);
	for(int i=19;i>=0;i--)
		if(dep[f[i][x]]>=dep[y])
			x=f[i][x];
	if(x==y)return x;
	for(int i=19;i>=0;i--)
		if(f[i][x]^f[i][y])
			x=f[i][x],y=f[i][y];
	return f[0][x];
}
inline int Dis(int x,int y){
	return dis[x]+dis[y]-2*dis[lca(x,y)];
}
int vis[N],mdis[M][M];
int Mdis[M][N];
inline void solve(int u,int v){
	int ans=Dis(u,v);
	for(int i=1;i<=pn;i++)
		for(int j=1;j<=pn;j++)
			if(i^j)ans=min(ans,Mdis[i][u]+mdis[i][j]+Mdis[j][v]);
	cout<<ans<<'\n';
}
signed main(){
	n=in,m=in;
	for(int i=1;i<=m;i++)
		E[i].u=in,E[i].v=in,E[i].w=in;
	for(int i=1;i<=n;i++)fa[i]=i;
	sort(E+1,E+1+m);
	
	for(int i=1,u=E[i].u,v=E[i].v,w=E[i].w;i<=m;i++,u=E[i].u,v=E[i].v,w=E[i].w)
		if(merge(u,v))T.insert(u,v,w),T.insert(v,u,w);
		else vip[++pn]=u,vip[++pn]=v,vis[i]=1;
		
	dfs(1,0);
	
	sort(vip+1,vip+1+pn);
	pn=unique(vip+1,vip+1+pn)-(vip+1);
	
	for(int i=1;i<=pn;i++)
		for(int j=1;j<=pn;j++)
			mdis[i][j]=Dis(vip[i],vip[j]);		
	for(int i=1,u=E[i].u,v=E[i].v,w=E[i].w;i<=m;i++,u=E[i].u,v=E[i].v,w=E[i].w)
		if(vis[i])u=bin(u),v=bin(v),mdis[u][v]=mdis[v][u]=min(mdis[u][v],w);	
	for(int k=1;k<=pn;k++)
		for(int i=1;i<=pn;i++)
			for(int j=1;j<=pn;j++)
				mdis[i][j]=min(mdis[i][j],mdis[i][k]+mdis[k][j]);		
	for(int i=1;i<=pn;i++)
		for(int j=1;j<=n;j++)
			Mdis[i][j]=Dis(vip[i],j);
			
	q=in;
	for(int i=1,u,v;i<=q;i++)
		u=in,v=in,solve(u,v);
	return 0;
}
posted @ 2022-03-08 19:20  llmmkk  阅读(18)  评论(0编辑  收藏  举报