如何判断多个边构成的集合是否能成为一个图中MST的子边集?
昨天去打了牛客的哈尔滨华德学院第十六届程序设计竞赛(同步赛),最后两题没写,光顾最后一题了,现在补了,也获得了些知识点
其实思想不会很难,估计看一会就懂了。题解说时可撤销并查集,但是我不太知道这个知识点,所以就按照我自己的思路,赛后继续优化去了。
我们首先去思考,一个边存在于一个图中MST的可能边集的判法。
一个图中的MST,显然我们可以用Prim或者Kruskal去解决。本次就得需要Kruskal了
Kruskal本质就是对边的大小去排序,然后用并查集去维护边连的两个点,能合并就合并。
好了,那么我们就会发现,如果一些边的值一样,其实对于这些边先走谁都可以,又由于小于这些值的边我们已经走了,所以不管如何在还没遍历这些值相同的边时,构成的并查集状态是一定的!
所以对于一条边来讲,我们只需去查看边同值时其作为第一条遍历边,其两端有没有被并查集连起来。这个其实可以直接在使用Kruskal得出,因为我可以先遍历这些边,但是用并查集,然后用个map或pair去保存下每个边所连端点所在并查集即可,最好是两端不同才保存。
好了,现在一条边会了,多条边肯定有有办法推广。
其实多条边,无非就是有些值相同,有些不同。那么对于一些同值边来讲,在遍历这个值之前构成的并查集是一定的,我们先遍历这些边,把之前所存储端点所在并查集拿出来,此时我们把这些端点所属并查集看成对应数值的点,再用个并查集(称为临时并查集)去连这些点,如果两个点在同一临时并查集,那么就说明这个边集一定不行。如此我们就解决完了这些同值的边,好了那么其他边呢?重复上述过程即可。注意要对临时并查集初始化,还有如果一个边两个端点所在并查集一样,这个边集必定不行。
好了,现在你已经懂了大致思路,这里给个多次询问边集是否属于图的MST的边集的子集且且图不一定连通的题目
这个能做对,你肯定就彻底理解了,可以使用可撤销并查集(这个我目前还没学,哈哈)
题目链接:https://ac.nowcoder.com/acm/contest/108665/K


思路:首先图不一定连通,那么我们就老老实实dfs染色+vis标记。随后我们把每条边所连端点的颜色进行分图存边,并根据边的大小进行排序。随后对于一个分图来讲,我们还需要按照所有权值相同的边进行分别处理。主要是记录此时边所连的两个端点是否属于不同端点mp和记录下两个端点所属的并查集mb。处理好这些边后,用并查集把这些边相连。如此就可以进行询问了,对于一个询问来讲,我们需要set去存每个边的权值,然后又进行分边集处理,对于图是否连通来讲,在存储遍历时,我们比较下现在边的端点颜色和第一个边所连的端点是否相同即可,顺带还要检查下这个边的mp是否存在。如果上述都ok,那么我就进行分边集后的遍历,这里要使用个临时并查集(好像也可以直接用原来的),对于这个并查集先进行初始化(这要对我需要使用的点初始化),然后同值的边相连看看是否会出现两个端点在同一临时并查集的情况,如果要是没问题,那么就去检查下一个同值得边集,如果上述还ok,那么恭喜你,输出YES即做完本题。
#include<iostream>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<algorithm>
#include<deque>
#include<cctype>
#include<string.h>
#include<cstring>
#include<math.h>
#include<time.h>
#include<random>
#include<functional>
#include<stack>
#include<unordered_map>
#include<string>
#include<bitset>
#define ll long long
#define lowbit(x) (x & -x)
#define endl "\n"// 交互题记得删除
// #include <ext/pb_ds/assoc_container.hpp>
// #include <ext/pb_ds/tree_policy.hpp>
// using namespace __gnu_pbds;
using namespace std;
mt19937 rnd(time(0));
const ll mod = 1e9 + 7;
//const ll p=rnd()%mod;
#define F first
#define S second
// tree<ll,null_type,less<ll>,rb_tree_tag,tree_order_statistics_node_update> f;
//find_by_order(k),找第k位(从小到大)的数字,order_of_key(x),x的排名
ll ksm(ll x, ll y)//快速幂
{
ll ans = 1;
x %= mod;
while (y)
{
if (y & 1)
{
ans = ans * x % mod;
}
x = x * x % mod;
y >>= 1;
}
return ans % mod;
}
// inline ll read()//快读
// {
// register ll x = 0, f = 1;
// char c = getchar();
// while (c < '0' || c>'9')
// {
// if (c == '-') f = -1;
// c = getchar();
// }
// while (c >= '0' && c <= '9')
// {
// x = (x << 3) + (x << 1) + (c ^ 48); //等价于x*10+c-48,使用位运算加速
// c = getchar();
// }
// return x * f;
// }
void fio()//加速流
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
}
struct s
{
ll w,l,r,id;
friend bool operator<(const s& a, const s& b)
{
return a.w<b.w;
};
};
ll e1[8] = { 0,1,0,-1,1,1,-1,-1 };
ll e2[8] = { 1,0,-1,0,1,-1,-1,1 };//前面四个为右边开始的逆时针,后面四个为角落
ll zs[2500000];
ll cnt = 0;
void ola(ll x)
{
vector<bool>vis(x + 5);
for (ll i = 2; i <= x; i++)
{
if (!vis[i])zs[++cnt] = i;
for (ll j = 1; i * zs[j] <= x; j++)
{
vis[i * zs[j]] = 1;
if (i % zs[j] == 0)break;
}
}
}
int main()
{
fio();
ll t=1;
// cin>>t;
while(t--)
{
ll n,m;
cin>>n>>m;
pair<ll,ll>cn[m+5];
vector<ll>vv(m+5),co(n+5,0);
vector<pair<ll,ll>>g[m+5];
for(ll i=1;i<=m;i++)
{
ll l,r,w;
cin>>l>>r>>w;
if(l>r)swap(l,r);
cn[i]={l,r};
vv[i]=w;
g[l].push_back({i,r});
g[r].push_back({i,l});
}
vector<ll>b(n+5);
for(ll i=1;i<=n;i++)
{
b[i]=i;
}
function<ll(ll)>find=[&](ll x)
{
if(b[x]==x)return x;
else return b[x]=find(b[x]);
};//ac
vector<bool>vis(n+5,0);
ll cnt=0;
function<void(ll)>dfs=[&](ll x)
{
if(vis[x])return ;
vis[x]=1;
co[x]=cnt;
for(auto [l,r]:g[x])
{
dfs(r);
}
};
for(ll i=1;i<=n;i++)
{
if(co[i])continue;
else cnt++;
dfs(i);
}//ac
vector<s>cs[n+5];//分块之后得编号
for(ll i=1;i<=n;i++)
{
for(auto [l,r]:g[i])
{
cs[co[i]].push_back({vv[l],i,r,l});
}
}
map<pair<ll,ll>,ll>mp;
map<ll,pair<ll,ll>>mb;
for(ll i=1;i<=cnt;i++)
{
sort(cs[i].begin(),cs[i].end());
ll u=0;
vector<s>k;
for(auto &j:cs[i])
{
if(j.l>j.r)swap(j.l,j.r);
if(u!=j.w)
{
if(u!=0)
{
for(auto d:k)
{
ll l=d.l,r=d.r;
ll x=find(l),y=find(r);
if(x==y)continue;
else mp[{l,r}]=d.w,mb[d.id]={x,y};
}
for(auto d:k)
{
ll l=d.l,r=d.r;
ll x=find(l),y=find(r);
if(x==y)continue;
b[x]=y;
}
}
k.clear();
k.push_back(j);
u=j.w;
}
else k.push_back(j);
}
if(u!=0)
{
for(auto d:k)
{
ll l=d.l,r=d.r;
ll x=find(l),y=find(r);
if(x==y)continue;
else mp[{l,r}]=d.w,mb[d.id]={x,y};
}
for(auto d:k)
{
ll l=d.l,r=d.r;
ll x=find(l),y=find(r);
if(x==y)continue;
b[x]=y;
}
}
}//ac
vector<ll>c(n+5,0);
function<ll(ll)>fd=[&](ll x)
{
if(c[x]==x)return x;
else return c[x]=fd(c[x]);
};
ll q;
cin>>q;
while(q--)
{
ll n;
cin>>n;
vector<ll>a(n+5);
set<ll>ls;
map<ll,vector<ll>>sj;
ll ok=0;
for(ll i=1;i<=n;i++)
{
cin>>a[i];
auto [l,r]=mb[a[i]];
ll x=cn[a[i]].first;
ll y=cn[a[i]].second;
if(co[x]!=co[cn[a[1]].first]||mp.find({x,y})==mp.end())ok=1;
c[l]=l,c[r]=r;
ls.insert(vv[a[i]]);
sj[vv[a[i]]].push_back(a[i]);
}
for(auto j:ls)
{
for(auto id:sj[j])
{
auto[x,y]=mb[id];
ll l=fd(x);
ll r=fd(y);
if(l==r)ok=1;
else c[l]=r;
}
for(auto id:sj[j])
{
auto[x,y]=mb[id];
c[x]=x,c[y]=y;
}
//cout<<endl;
}
if(ok)cout<<"NO"<<endl;
else cout<<"YES"<<endl;
}
}
return 0;
}

浙公网安备 33010602011771号