由于到达关系具有传递性,可以考虑不断将若干个可以相互到达的点缩点,并且当两个点只能单向到达时,能到达另一个点的点一定不是最小值
由此,我们来考虑dfs,即不断从一个节点开始,遍历其可以到达的点,当发现了环即将这些点合并(启发式合并),当发现了已经完全搜过(不在栈中)的点即一定不能作为最小值
在实现上,有一些困难,注意以下细节:
1.对每一个点还要维护一个钥匙集合,也参与启发式合并
2.启发式合并时可能有新的边可以到达,在加入时判定即可
3.由于要弹出元素,且不像强连通分量一样保证必然弹出,因此建议手动模拟栈来实现
4.在搜过一条边后将其弹出边集,以避免合并后被其他点重复搜索
5.判定是否遍历到只能单向到达的点,可以在搜索结束后再判定
1 #include<bits/stdc++.h> 2 #include"keys.h" 3 using namespace std; 4 #define N 300005 5 #define vi vector<int> 6 #define fi first 7 #define se second 8 stack<int>st; 9 set<int>key[N]; 10 set<int>::iterator it1; 11 vector<int>ans,G0[N]; 12 set<pair<int,int> >G1[N]; 13 set<pair<int,int> >::iterator it2; 14 int n,m,mn,dfn[N],vis[N],f[N],sz[N]; 15 int find(int k){ 16 if (k==f[k])return k; 17 return f[k]=find(f[k]); 18 } 19 int get_sum(int k){ 20 return key[k].size()+G0[k].size()+G1[k].size(); 21 } 22 void add(int x,int y,int z){ 23 x=find(x); 24 if (key[x].find(z)!=key[x].end())G0[x].push_back(y); 25 else G1[x].insert(make_pair(z,y)); 26 } 27 void merge(int x,int y){ 28 x=find(x),y=find(y); 29 if (x==y)return; 30 if (get_sum(x)<get_sum(y))swap(x,y); 31 f[y]=x; 32 sz[x]+=sz[y]; 33 for(it1=key[y].begin();it1!=key[y].end();it1++){ 34 int k=(*it1); 35 key[x].insert(k); 36 while (1){ 37 it2=G1[x].lower_bound(make_pair(k,0)); 38 if ((it2==G1[x].end())||((*it2).fi!=k))break; 39 G0[x].push_back((*it2).se); 40 G1[x].erase(it2); 41 } 42 } 43 key[y].clear(); 44 for(int i=0;i<G0[y].size();i++)G0[x].push_back(G0[y][i]); 45 G0[y].clear(); 46 for(it2=G1[y].begin();it2!=G1[y].end();it2++)add(x,(*it2).se,(*it2).fi); 47 G1[y].clear(); 48 } 49 void dfs(int k){ 50 st.push(k); 51 while (!st.empty()){ 52 k=st.top(); 53 dfn[k]=1; 54 if (G0[k].empty()){ 55 vis[k]=1; 56 st.pop(); 57 continue; 58 } 59 int x=find(G0[k].back()); 60 G0[k].pop_back(); 61 if (!dfn[x]){ 62 st.push(x); 63 continue; 64 } 65 if (vis[x])continue; 66 while (st.top()!=x){ 67 merge(st.top(),k); 68 st.pop(); 69 } 70 merge(st.top(),k); 71 st.pop(); 72 st.push(find(k)); 73 } 74 } 75 void check(int x,int y,int z){ 76 x=find(x),y=find(y); 77 if (x!=y){ 78 if (key[x].find(z)!=key[x].end())vis[x]=1; 79 if (key[y].find(z)!=key[y].end())vis[y]=1; 80 } 81 } 82 vi find_reachable(vi r,vi u,vi v,vi c){ 83 n=r.size(),m=u.size(); 84 for(int i=1;i<=n;i++){ 85 f[i]=i,sz[i]=1; 86 key[i].insert(r[i-1]); 87 } 88 for(int i=0;i<m;i++){ 89 u[i]++,v[i]++; 90 add(u[i],v[i],c[i]); 91 add(v[i],u[i],c[i]); 92 } 93 for(int i=1;i<=n;i++) 94 if (!dfn[i])dfs(i); 95 memset(vis,0,sizeof(vis)); 96 for(int i=0;i<m;i++)check(u[i],v[i],c[i]); 97 mn=0x3f3f3f3f; 98 for(int i=1;i<=n;i++) 99 if (!vis[find(i)])mn=min(mn,sz[find(i)]); 100 for(int i=1;i<=n;i++) 101 if ((!vis[find(i)])&&(sz[find(i)]==mn))ans.push_back(1); 102 else ans.push_back(0); 103 return ans; 104 }