思路
反向建图,贪心跑bfs
反向建图权值从大到小跑bfs,来确定当前权值可以到达的点,在正常图(正向建边)中即是能到达它的点,然后开个 v i s vis vis数组记录一下点是否来过,贪心下每个点只更新一次,线性复杂度.
Code
const int inf = 0x3f3f3f3f;
const int INF = ~0ULL;
const int N = 1e6+10;
int n,m;
struct node{
int id,w;
bool operator<(const node&t) const{
if(w==t.w) return id < t.id;
return w > t.w;
}
}a[100005];
vector<int>g[100005];
int in[100005];
int f[100005];
bool st[N];
map<int,int> mp;
void bfs(int u){
queue<int> q;
q.push(u);
st[u] = 1;
while(q.size()){
int t = q.front();q.pop();
for(auto i:g[t]){
if(!st[i]){
t = mp[i];
a[t].w = max(a[t].w,a[mp[u]].w);
st[i] = 1;
q.push(i);
}
}
}
}
signed main()
{
cin>>n>>m;
forr(i,1,n) cin >> a[i].w,a[i].id = i;
while(m--){
int u,v;
cin>>u>>v;
g[v].push_back(u);
}
sort(a+1,a+1+n);
forr(i,1,n) mp[a[i].id] = i;
forr(i,1,n){
bfs(a[i].id);
}
int res = 0;
forr(i,1,n) res += a[i].w;
cout << res << endl;
return 0;
}
T
a
r
j
a
n
+
d
f
s
Tarjan+dfs
Tarjan+dfs
用
t
a
r
j
a
n
tarjan
tarjan算法缩完点之后直接跑一边
d
f
s
dfs
dfs,因为
t
a
r
j
a
n
tarjan
tarjan之后强连通分量是逆拓扑序,直接倒着跑一遍
d
f
s
dfs
dfs更新缩完点之后每个点的最大权值
typedef long long ll;
int pri[16] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53};
const int inf = 0x3f3f3f3f;
const int INF = ~0ULL;
const int N = 1e6+10;
int n,m;
vector<int> g[100005],v[100005],scc[100005];
int dfn[100005],low[100005],id[100005];// id 结点在的强连通分量编号
int tim,cnt; // time 时间戳 cnt 连通分量个数
int stk[100005],top;
bool ins[100005];//是否在栈内
int num[100005];
int w[100005],val[100005];
bool st[100005];
int in[100005];
void tarjan(int u){
dfn[u] = low[u] = ++tim;
stk[++top] = u,ins[u] = 1;
for(auto v:g[u]){
if(!dfn[v]){
tarjan(v);
low[u] = min(low[u],low[v]);
}
else if(ins[v]) low[u] = min(low[u],low[v]);
}
if(low[u] == dfn[u]){
cnt++;int y;
do{
y = stk[top--]; id[y] = cnt;
ins[y] = 0;scc[cnt].push_back(y);
}while(u != y);
}
}
void dfs(int u){
st[u] = 1;
for(auto j:v[u]){
if(!st[j]) dfs(j);
val[u] = max(val[u],val[j]);
}
}
signed main()
{
cin >> n >> m;
forr(i,1,n) cin >> w[i];
while(m--){
int u,v;
cin>>u>>v;
g[u].push_back(v);
}
forr(i,1,n) if(!dfn[i]) tarjan(i);
forr(i,1,n){
for(auto j:g[i]){
if(id[i] != id[j])
v[id[i]].push_back(id[j]),in[id[j]]++;
}
}
// forr(i,1,cnt){
// cout << i <<" ";
// for(auto j:v[i]) cout << j <<" ";
// cout << endl;
// }
forr(i,1,cnt){
int res = 0;
for(auto j:scc[i]){
res = max(res,w[j]);
}
val[i] = res;
}
for(int i = cnt;i;i--) if(!st[i]) dfs(i);
// forr(i,1,cnt) cout << val[i] << endl;
int res = 0;
forr(i,1,cnt) res += scc[i].size()*val[i];
cout << res << endl;
return 0;
}