The Shortest Statement
题解
看到此题应该很容易想到最短路,但是由于,肯定不能直接跑最短路。
但是我们很快就发现了一个奇怪的数据范围,。
这说明,在构成一棵生成树后,剩下来的边不会超过21条。而我们将一条边插入在树上后会构成一棵基环树,而将其环上的一条边去掉便会形成一棵新树。
我们发现,将一个点到其它点的最短路径标出来后一定会形成一棵新的生成树,而路径肯定是其树上的一条路径。
当然不可能把全部树建出来跑,不说时间,空间都会炸。
但我们发现,我们其实还是可以先建一棵树出来,剩下的边跑最短路。
对于一条路径,它要么全在生成树上,要么会包含其它的非树边。而对于其它的非树边,总共21条,跑了42次最短路,可以将其带入到路径中,一个一个计算其的最短路径长度。
总时间复杂度,好奇怪的复杂度
源码
#include<bits/stdc++.h>
using namespace std;
#define MAXN 100005
typedef long long LL;
typedef unsigned long long uLL;
const LL INF=0x7f7f7f7f7f7f;
const int mo=1e9+7;
typedef pair<int,LL> pii;
template<typename _T>
void read(_T &x){
_T f=1;x=0;char s=getchar();
while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}
x*=f;
}
int n,m,fa[MAXN],dep[MAXN];
int Q,f[MAXN][20],head[MAXN],tot;
LL dist[MAXN],dis[50][MAXN];
bool vis[MAXN];
struct step{
LL t;int id;
bool friend operator < (const step &x,const step &y){
return x.t>y.t;
}
};
priority_queue<step> q;
struct ming{
int u,v;LL w;
bool friend operator < (const ming &x,const ming &y){
return x.w<y.w;
}
}a[MAXN];
vector<int> vec;
struct edge{int to,nxt;LL paid;}e[MAXN<<1];
void addEdge(int u,int v,int w){e[++tot]=(edge){v,head[u],w};head[u]=tot;}
void makeSet(int x){for(int i=1;i<=x;i++)fa[i]=i;}
int findSet(int x){return fa[x]==x?x:fa[x]=findSet(fa[x]);}
void unionSet(int a,int b){
int u=findSet(a),v=findSet(b);
if(u==v)return ;fa[u]=v;
}
void dfs(int u,int father){
dep[u]=dep[father]+1;f[u][0]=father;
for(int i=1;i<18;i++)f[u][i]=f[f[u][i-1]][i-1];
for(int i=head[u];i;i=e[i].nxt){
int v=e[i].to;if(v==father)continue;
dist[v]=dist[u]+e[i].paid;dfs(v,u);
}
}
int lca(int a,int b){
if(dep[a]>dep[b])swap(a,b);
for(int i=17;i>=0;i--)if(dep[f[b][i]]>=dep[a])b=f[b][i];
if(a==b)return a;
for(int i=17;i>=0;i--)if(f[a][i]!=f[b][i])a=f[a][i],b=f[b][i];
return f[a][0];
}
void Dijkstra(int u,int id){
while(!q.empty())q.pop();
for(int i=1;i<=n;i++)dis[id][i]=INF,vis[i]=0;
dis[id][u]=0;q.push((step){0,u});
while(!q.empty()){
int t=q.top().id;q.pop();
if(vis[t])continue;vis[t]=1;
//printf("%d %d:%d\n",id,t,dis[id][t]);
for(int i=head[t];i;i=e[i].nxt){
int v=e[i].to;LL w=e[i].paid;
if(dis[id][t]+w<dis[id][v])
dis[id][v]=dis[id][t]+w,
q.push((step){dis[id][v],v});
}
}
//printf("%d %d:",u,id);
//for(int i=1;i<=n;i++)printf("%d ",dis[id][i]);puts("");
}
signed main(){
read(n);read(m);
for(int i=1;i<=m;i++){
int u,v;LL w;
read(u);read(v);read(w);
a[i]=(ming){u,v,w};
}
sort(a+1,a+m+1);makeSet(n);
for(int i=1;i<=m;i++){
int u=findSet(a[i].u),v=findSet(a[i].v);
//printf("%d %d %d\n",u,v,a[i].w);
if(u==v)vec.push_back(i);
else {
unionSet(u,v);
addEdge(a[i].u,a[i].v,a[i].w);
addEdge(a[i].v,a[i].u,a[i].w);
}
}
dfs(1,1);int siz=vec.size();
for(int i=0;i<siz;i++)
addEdge(a[vec[i]].u,a[vec[i]].v,a[vec[i]].w),
addEdge(a[vec[i]].v,a[vec[i]].u,a[vec[i]].w);
for(int i=0;i<siz;i++){
Dijkstra(a[vec[i]].u,i*2+1);
Dijkstra(a[vec[i]].v,i*2+2);
}
read(Q);
for(int i=1;i<=Q;i++){
int u,v;read(u);read(v);
LL ans=dist[u]+dist[v]-2*dist[lca(u,v)];
for(int j=0;j<siz;j++)
ans=min(ans,dis[j*2+1][u]+dis[j*2+2][v]+a[vec[j]].w),
ans=min(ans,dis[j*2+1][v]+dis[j*2+2][u]+a[vec[j]].w);
printf("%lld\n",ans);
}
return 0;
}