【题解】2019,6.10模拟赛 (删边最小生成树)
Description
给出一张 \(n\) 个点 \(m\) 条边(带权)的图,每次有 \(Q\) 组询问,每次询问删除一条边后的最小生成树的耗费,如果不连通输出 "Not Connected"。
Sample Input
4 4
1 2 3
1 3 5
2 3 9
2 4 1
4
1
2
3
4
Sample Output
15
13
9
Not Connected
Hint
\(n\leqslant 100000,m \leqslant 500000\)
Solution
这题不得鸟!!!
我们考虑删掉一条边之后,我们肯定是要找一条边来代替它。
很显然一个环上的边都可以替代别的边,那么我们只要不停的找环然后把它上面最小的边找出来,那么这个环上的边都可以由他来替代。
那么怎么找环呢?
有好多办法,我们考虑一种比较简单的,就先做最小生成树然后枚举非树边,然后我们再暴力跳到这条边两个端点的LCA,这之间就是个环,那么想一想的话代码就很简单了。
但是还是有一个问题,这个复杂度最坏情况下会退化成 \(O(N*M)\)
...
虽然我们可以打标记让已经更新过了的边不在更新,但是暴力跳的复杂度还是很高。
我们可以考虑把走过了的边路径压缩,没错,我们可以用并查集,这样就有复杂度保证了。
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize("Ofast")
#pragma GCC optimize("inline")
#include<bits/stdc++.h>
using namespace std;
#define R register
inline char gc(){
static char buf[1<<20],*p1=buf,*p2=buf;
if(p1==p2){
p2=(p1=buf)+fread(buf,1,1<<20,stdin);
if(p1==p2) return EOF;
}
return *p1++;
}
inline int read(){
int x=0;char ch=gc();
while(!isdigit(ch)) ch=gc();
while(isdigit(ch)) x=x*10+ch-'0',ch=gc();
return x;
}
inline void write(int x){
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);
putchar(x%10+'0');
}
int En=0,ans;
const int N=1e5+5,M=5e5+5,INF=1E9;
int fa[N],dep[N],res[M];
int TreeCost[N],TreeFa[N],TreeId[N];
bool IsUsed[M],Updated[M];
struct node {
int to,dis,id;
};
vector <node> G[N];
struct edge {
int from,to,dis,id;
}E[M];
inline int getf(int x){
return (fa[x]==x)?x:fa[x]=getf(fa[x]);
}
bool cmp(edge a,edge b){
return a.dis<b.dis;
}
inline void dfs(int u,int f){
dep[u]=dep[f]+1;
TreeFa[u]=f;
for(int i=0;i<(int)G[u].size();++i){
int v=G[u][i].to;
if(v==f) continue;
TreeCost[v]=G[u][i].dis;
TreeId[v]=G[u][i].id;
dfs(v,u);
}
}
inline void update(int a,int b,int tmp){
a=getf(a),b=getf(b);
while(a!=b){
if(dep[a]>dep[b]){
res[TreeId[a]]=ans-TreeCost[a]+tmp;
fa[a]=getf(TreeFa[a]);
a=fa[a];
}
else {
res[TreeId[b]]=ans-TreeCost[b]+tmp;
fa[b]=getf(TreeFa[b]);
b=fa[b];
}
}
}
int main(){
int n=read(),m=read();
for(R int i=1;i<=m;++i){
int u=read(),v=read(),w=read();
E[++En]=(edge){u,v,w,i};
res[i]=INF;
}
for(int i=1;i<=n;++i) fa[i]=i;
sort(E+1,E+En+1,cmp);
int num=0;
for(R int i=1;i<=m;++i){
int fx=getf(E[i].from),fy=getf(E[i].to);
if(fx!=fy){
fa[fx]=fy;
G[E[i].from].push_back((node){E[i].to,E[i].dis,E[i].id});
G[E[i].to].push_back((node){E[i].from,E[i].dis,E[i].id});
num++;
ans+=E[i].dis;
IsUsed[E[i].id]=true;
}
if(num==n-1) break;
}
dfs(1,1);
for(int i=1;i<=n;++i) fa[i]=i;
for(R int i=1;i<=m;++i)
if(!IsUsed[E[i].id]){
int a=E[i].from,b=E[i].to;
update(a,b,E[i].dis);
}
R int q=read();
while(q--){
int tmp=read();
if(IsUsed[tmp]){
if(res[tmp]!=INF) write(res[tmp]),putchar('\n');
else puts("Not connected");
}
else write(ans),putchar('\n');
}
return 0;
}