CF 160D Edges in MST 最小生成树的性质,寻桥,缩点,批量处理 难度:3
http://codeforces.com/problemset/problem/160/D
这道题要求哪条边存在于某个最小生成树中,哪条边不存在于最小生成树中,哪条边绝对存在于最小生成树中
明显桥边一定存在于所有最小生成树中,然而怎么处理存在某个最小生成树的边呢?
借助kruskal算法的性质,由小到大,每次处理同一权值的边,如果边连接的点已经联通就不要管,否则那些处理的边一定存在于某最小生成树上
批量处理的思想很巧妙
#include <cstdio> #include <vector> #include <stack> #include <algorithm> using namespace std; const int maxn=2e5+5; int first[maxn]; struct edge{ int t,ind,nxt; }e[maxn]; int from[maxn],to[maxn],cost[maxn],index[maxn]; int sta[maxn]; int n,m,len; void addedge(int f,int t,int ind,int i){ e[i].nxt=first[f]; first[f]=i; e[i].t=t; e[i].ind=ind; } int par[maxn],num[maxn]; int fnd(int x){return par[x]==x?x:par[x]=fnd(par[x]);} void unit(int a,int b){ if(fnd(a)==fnd(b))return; num[fnd(b)]+=num[fnd(a)]; num[fnd(a)]=0; par[fnd(a)]=fnd(b); } bool cmp(int a,int b) {return cost[a]<cost[b];} int dfn[maxn],low[maxn],cnt; void dfs(int s,int f){ dfn[s]=low[s]=++cnt; for(int p=first[s];p!=0;p=e[p].nxt){ int t=e[p].t; if(p==(((f-1)^1)+1))continue; if(dfn[t]==0){ dfs(t,p); if(low[t]>dfn[s]){ sta[e[p].ind]=2; } else{ low[s]=min(low[s],low[t]); } } else { low[s]=min(low[s],dfn[t]); } } } int st[maxn],tail; void kruskal2(){ sort(index,index+m,cmp); for(int i=0;i<m&&num[fnd(1)]<n;){ int j=i; while(cost[index[i]]==cost[index[j]]&&j<m){j++;} for(int k=i;k<j;k++){ int indk=index[k]; if(fnd(from[indk])!=fnd(to[indk])){ st[tail++]=indk; sta[indk]=1; } } for(int p=0;p<tail;p++){ int tp=st[p]; int f=fnd(from[tp]),t=fnd(to[tp]); addedge(f,t,tp,++len); addedge(t,f,tp,++len); } for(int p=0;p<tail;p++){ int tp=st[p]; int f=fnd(from[tp]),t=fnd(to[tp]); dfs(f,0); unit(f,t); } cnt=0; len=0; for(int p=0;p<tail;p++){ int tp=st[p]; int f=fnd(from[tp]),t=fnd(to[tp]); first[f]=first[t]=0; dfn[f]=dfn[t]=0; } i=j; tail=0; } } int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=n;i++){par[i]=i;num[i]=1;} for(int i=0;i<m;i++){ scanf("%d%d%d",from+i,to+i,cost+i); index[i]=i; } kruskal2(); for(int i=0;i<m;i++){ if(sta[i]==2)puts("any"); else if(sta[i]==1)puts("at least one"); else puts("none"); } return 0; }