摘要:选了一些好题。
跳伞登山赛
原题:P3916
题意:
给出 \(N\) 个点,\(M\) 条边的有向图,对于每个点 \(v\),求从点 \(v\) 出发,能到达的编号最大的点。\(1 \le N,M \le 10^5\)。
solution:
按题意枚举,时间复杂度 \(O(NM)\)。超时
正难则反,考虑建反图,看较大的点可以反向到达哪些点。
每个点访问一次,这个值就是最优的,因为之后如果再访问到这个结点那么答案肯定没当前大了。所以要倒着枚举节点去遍历。
code:
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
int head[200005],cnt;
struct data{int to;int next;
};
data edge[200005];
void add_edge(int from,int to){cnt++;edge[cnt].to=to;edge[cnt].next=head[from];head[from]=cnt;
}
int n,m;
int ans[100005];
void dfs(int u,int maxx) {if(ans[u]) return;ans[u]=maxx;for(int i=head[u];i;i=edge[i].next) {int v=edge[i].to;dfs(v,maxx);}
}
signed main(){cin>>n>>m;for(int i=1;i<=m;i++) {int u,v;cin>>u>>v;add_edge(v,u);}for(int i=n;i>=1;i--) {dfs(i,i);}for(int i=1;i<=n;i++) {cout<<ans[i]<<" ";}return 0;
}