洛谷 P4742 【[Wind Festival]Running In The Sky】
tarjan模板题
这道题tarjan加记忆化搜索就行,记忆化搜索中,就可以完美解决最大值和最长路。直接讲比较抽象,上代码:
#include <bits/stdc++.h>
using namespace std;
int n , m , now , tot , ans1 , ans2;
int dfn[200010] , low[200010] , home[200010] , a[200010] , dis[200010] , vis[200010] , kp[200010];
int f[200010] , maxx[200010];
stack<int> s;
vector<int> e[200010];
vector<int> ne[200010]; //存重建的图
void tarjan(int x){
dfn[x] = low[x] = ++now;
s.push(x);
vis[x] = 1;
for(int i = 0; i < e[x].size(); i++){
int nx = e[x][i];
if(!dfn[nx]){
tarjan(nx);
low[x] = min(low[x] , low[nx]);
}else if(vis[nx]) low[x] = min(low[x] , dfn[nx]);
}
if(dfn[x] == low[x]){
tot++;
while(!s.empty()){
int top = s.top();
s.pop();
kp[tot] = max(kp[tot] , a[top]); //统计下最大值
vis[top] = 0;
dis[tot] += a[top]; //统计点的和
home[top] = tot;
if(top == x) break;
}
}
}
void dfs(int x){
if(f[x]) return;
f[x] = dis[x];
int ans = 0 , ansmax = 0;
for(int i = 0; i < ne[x].size(); i++){
int nx = ne[x][i];
dfs(nx);
if(f[nx] > ans){ //最长路优先,其次最大值
ans = f[nx];
ansmax = maxx[nx];
}else if(f[nx] == ans){
if(maxx[nx] > ansmax) ansmax = maxx[nx];
}
}
f[x] += ans; //选择最长路
maxx[x] = max(ansmax , kp[x]);
}
int main(){
cin >> n >> m;
for(int i = 1; i <= n; i++) cin >> a[i];
for(int i = 1; i <= m; i++){
int x , y;
cin >> x >> y;
e[x].push_back(y);
}
for(int i = 1; i <= n; i++)
if(!dfn[i]) tarjan(i);
for(int i = 1; i <= n; i++)
for(int j = 0; j < e[i].size(); j++){ //重建
int nx = e[i][j];
if(home[nx] != home[i]) ne[home[i]].push_back(home[nx]);
}
for(int i = 1; i <= tot; i++) dfs(i); //记忆化搜索
for(int i = 1; i <= tot; i++) //枚举答案
if(f[i] > ans1){
ans1 = f[i];
ans2 = maxx[i];
}else if(f[i] == ans1){
if(maxx[i] > ans2) ans2 = maxx[i];
}
cout << ans1 << " " << ans2;
return 0;
}