题意:
就是给你n个点m条边形成一个图,然后和k次查询,每次查询给你一条边和一个权值,问你如果把这个边放到图里面,然后是否这个边会成为原图最小生成树的边。
思考:
刚开始看到想了想暴力,肯定不行,然后想先把图建出来,然后再进行k次操作,每次操作的时候,看看这个边是否有必要加进来,但是怎么判断呢,刚开始想了个错的判断就是如果当前边的c<dis[a]||c<dis[b],dis代表每个点和他相连边的最小边,但是这是错的,画几个例子就看出来了,然后去想别的判断方法,从以前学最小生成树印象中都没有在中间判断是否可以换边的算法,那这种想法应该是错的。那建完图之后不能判断,是否能在建图的途中判断呢?反正一定要按边的权值来枚举,就是从边权最小的开始看,如果这些边中有一个边是需要用的,那么这个边就标记下来,然后把这些边连上。最后再判断k条边是否被标记即可。
代码:
struct node{
int a,b,c;
int id;
};
int T,n,m,k;
node va[N];
int vis[N];
int acc[N];
map<int,vector<node> > mp;
bool cmp(node A,node B)
{
return A.c<B.c;
}
int find(int x)
{
if(x!=acc[x]) acc[x] = find(acc[x]);
return acc[x];
}
void krukal()
{
for(int i=1;i<=n;i++) acc[i] = i;
for(auto now:mp)
{
for(auto t:now.se)
{
int a = t.a,b = t.b,c = t.c,id = t.id;
int t1 = find(a),t2 = find(b);
if(t1!=t2) vis[id] = 1;
}
for(auto t:now.se)
{
int a = t.a,b = t.b,c = t.c,id = t.id;
int t1 = find(a),t2 = find(b);
if(t1!=t2) acc[t1] = t2;
}
}
}
signed main()
{
IOS;
cin>>n>>m>>k;
for(int i=1;i<=m;i++)
{
int a,b,c;
cin>>a>>b>>c;
mp[c].pb({a,b,c,i});
}
for(int i=m+1;i<=m+k;i++)
{
int a,b,c;
cin>>a>>b>>c;
mp[c].pb({a,b,c,i});
}
krukal();
for(int i=m+1;i<=m+k;i++)
{
if(vis[i]) cout<<"Yes\n";
else cout<<"No\n";
}
return 0;
}
总结:
多思考多换思维方式,多多总结。