赞
踩
题目链接:Edges in MST
题意:给定n(1<=n<=1e5)个点,m(n-1=<m<=min(1e5,))条边,判断每条边是否存在所有最小生成树(MST)中,或存在至少一颗中,或不存在任何最小生成树中
题解:判断是否存在最小生成树中可以将边权从小到大排序,按照正常求最小生成树的方式,从小到大枚举边,不过这里把边权相同的边放一起处理,对于每个边如果连的两个点已经在一个块中,说明这条边就一定不存在任何MST(最小生成树)中,因为在之前有更小的边已经能替代当前边,否则当前边一定至少存在一颗最小生成树中,而存在所有MST中的边,我们可以发现这些边一定是桥(唯一联通两个块的边)对于当前枚举的边权,把每个块当成一个点(用当前并查集父亲代表点),当前权值中边如果能联通两个不同块就建边,然后利用tarjan求dfn和low,我们可以通过low和dfn判断(low[son]>dfn[now]那么说明该儿子怎么都走不回来,说明该边是唯一能走向儿子的边即桥)哪些边是桥,当然,要注意建的是双向边,所以tarjan中要注意不能往回走
不懂可以看代码和注释
- #include<iostream>
- #include<stack>
- #include<list>
- #include<set>
- #include<vector>
- #include<algorithm>
- #include<math.h>
- #include<numeric>
- #include<map>
- #include<cstring>
- #include<queue>
- #include<iomanip>
- #include<cmath>
- #include<queue>
- #include <bitset>
- #include<unordered_map>
- #ifndef local
- #define endl '\n'
- #endif */
- #define mkp make_pair
- using namespace std;
- using std::bitset;
- typedef long long ll;
- typedef long double ld;
- const int inf=0x3f3f3f3f;
- const ll MAXN=2e6+10;
- const ll N=1e5+100;
- const ll mod=1e9+7;
- const ll hash_p1=1610612741;
- const ll hash_p2=805306457;
- const ll hash_p3=402653189;
- //-----------------------------------------------------------------------------------------------------------------*/
- // ll head[MAXN],net[MAXN],to[MAXN],edge[MAXN]/*流量*/,cost[MAXN]//费用;
- /*
- void add(ll u,ll v,ll w,ll s){
- to[++cnt]=v;net[cnt]=head[u];edge[cnt]=w;cost[cnt]=s;head[u]=cnt;
- to[++cnt]=u;net[cnt]=head[v];edge[cnt]=0;cost[cnt]=-s;head[v]=cnt;
- }
- struct elemt{
- int p,v;
- };
- struct comp{
- public:
- bool operator()(elemt v1,elemt v2){
- return v1.v<v2.v;
- }
- };
- -----------------------------------
- 求[1,MAXN]组合式和逆元
- ll mi(ll a,ll b){
- ll res=1;
- while(b){
- if(b%2){
- res=res*a%mod;
- }
- a=a*a%mod;
- }
- return res;
- }
- ll fac[MAXN],inv[MAXN]
- fac[0]=1;inv[0]=1;
- for(int i=1;i<=MAXN;i){
- fac[i]=(fac[i-1]*i)%mod;
- inv[i]=mi(fac[i],mod-2);
- }
- ll C(int m,int n){//组合式C(m,n);
- if(!n){
- return 1;
- }
- return fac[m]*(inv[n]*inv[m*-n]%mod)%mod;
- }
- ---------------------------------
- unordered_map<int,int>mp;
- //优先队列默认小顶堆 , greater<int> --小顶堆 less<int> --大顶堆
- priority_queue<elemt,vector<elemt>,comp>q;
- set<int>::iterator it=st.begin();
- */
- // vector<vector<int>>edge; 二维虚拟储存坐标
- //-----------------------------------------------------------------------------------------------------------------*/
- map<int,int>mp[N];
- int f[N];
- int find(int x){
- return f[x]==x?x:f[x]=find(f[x]);
- }
- void merge(int x,int y){
- int fx=find(x),fy=find(y);
- if(fx!=fy){
- f[fx]=fy;
- }
- }
- struct line{
- int u,v,w,p;
- };
- bool comp(line v1,line v2){
- return v1.w<v2.w;
- }
- line a[N];
- int ans[5*N];
- vector<pair<int,int>>edge[N];//存边
- int cnt=0;
- int low[N];//代表能到达的最早的点
- int dfn[N];//当前标号
- void tarjan(int x,int pre){//pre记录的是来的边的编号
- low[x]=dfn[x]=++cnt;
- for(int i=0;i<edge[x].size();i++){
- int to=edge[x][i].first,id=edge[x][i].second;
- if(!dfn[to]){
- tarjan(to,id);
- low[x]=min(low[x],low[to]);
- if(low[to]>dfn[x]){//已经回不来了,说明这是桥
- ans[a[id].p]=2;//更新答案
- }
- }
- else if(id!=pre){//和tarjan不同的是这里不能往回走,特判下
- low[x]=min(low[x],dfn[to]);
- }
- }
- }
- int main(){
- /*cout<<setiosflags(ios::fixed)<<setprecision(8)<<ans<<endl;//输出ans(float)格式控制为8位小数(不含整数部分)*/
- /*cout<<setprecision(8)<<ans<<endl;//输出ans(float)格式控制为8位小数(含整数部分)*/
- ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);//同步流
- int n,m;
- cin>>n>>m;
- for(int i=1;i<=n;i++){
- f[i]=i;
- }
- for(int i=1;i<=m;i++){
- cin>>a[i].u>>a[i].v>>a[i].w;
- a[i].p=i;
- }
- sort(a+1,a+m+1,comp);
- for(int i=1;i<=m;i++){
- int r=i+1;
- while(r<=m&&a[r].w==a[i].w){//确定当前w对应边界
- r++;
- }
- cnt=0;
- for(int j=i;j<r;j++){//清空
- int fx=find(a[j].u),fy=find(a[j].v);
- if(fx!=fy){
- edge[fx].clear();
- edge[fy].clear();
- low[fx]=dfn[fx]=0;
- low[fy]=dfn[fy]=0;
- }
- }
- for(int j=i;j<r;j++){//清空
- int fx=find(a[j].u),fy=find(a[j].v);
- if(fx!=fy){
- ans[a[j].p]=1;//标记为至少存在MST中
- edge[fx].push_back({fy,j});//建边
- edge[fy].push_back({fx,j});
- }
- }
- for(int j=i;j<r;j++){//跑tarjan
- int fx=find(a[j].u),fy=find(a[j].v);
- if(fx!=fy&&!dfn[fx]){
- tarjan(fx,0);
- }
- }
- for(int j=i;j<r;j++){
- merge(a[j].u,a[j].v);//合并边
- }
- i=r-1;//跳到下一个w值
- }
- for(int i=1;i<=m;i++){
- if(ans[i]==0){
- cout<<"none"<<endl;
- }
- else if(ans[i]==2){
- cout<<"any"<<endl;
- }
- else{
- cout<<"at least one"<<endl;
- }
- }
- return 0;
- }

Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。