基本的想法就是对于每个点来一次bfs,求出它所能到达的点中最大的。这样是。
对于某个点,如果点能到达它,那么比
小的点都不必再搜。
于是可以想到一个优化:反向建边,点能到达点
即代表点
能
到达点。
基于上面的想法,只要从大往小搜,已经访问过的点不搜,即可保证答案的合法性。
(这是因为若之前访问过了,那么以前就已经带着比现在更优的信息(即源点编号),现在搜一定不会更优。)
#include<iostream>
#include<cstdio>
#include<queue>
#define maxn 100010
int read();
using namespace std;
queue<int>bfs;
struct Edge{
int to,nt;
}edge[maxn<<1];int tot,head[maxn];
void add(int a,int b){
edge[++tot].to=b;
edge[tot].nt=head[a];
head[a]=tot;
}
int n,m;
int vis[maxn];
int main(){
n=read(),m=read();
for(int i=1;i<=m;i++){
int x=read(),y=read();
add(y,x);
}
for(int k=n;k>=1;k--){//cout<<"i:"<<k<<endl;
if(!vis[k]){
while(!bfs.empty())
bfs.pop();
bfs.push(k);
while(!bfs.empty()){
int no=bfs.front();bfs.pop();
//cout<<no<<endl;cout<<"To:";
for(int i=head[no];i;i=edge[i].nt){
//cout<<edge[i].to<<' ';
if(edge[i].to<k&&vis[edge[i].to]==0){
vis[edge[i].to]=k;
bfs.push(edge[i].to);
}
}//cout<<endl;
}
}
}
for(int i=1;i<=n;i++)vis[i]=max(vis[i],i);
for(int i=1;i<=n;i++)cout<<vis[i]<<' ';
return 0;
}
int read(){
int s=0;char ch=getchar();
while(ch<'0'||ch>'9')ch=getchar();
while(ch>='0'&&ch<='9'){s=s*10+ch-'0';ch=getchar();}
return s;
}
京公网安备 11010502036488号