#include <iostream>
#include <cstdio>
#include <queue>
#include <cstring>
#include <string>
#include <cmath>
#include <vector>
#include <map>
#include <stack>
#include <algorithm>
//#include "myAlgorithm.h"
#define MAX 100005
#define OFFENCE (1e9 + 5)
#define INF (1e8 + 5)
#define eps 1e-9
#define Rep(s, e) for( int i = s; i <= e; i++)
#define Cep(e, s) for( int j = e; j >= s; j --)
#define PI acos(-1.0)
//#pragma comment(linker, "/STACK:36777216") ///传说中的外挂
using namespace std;
/**
想了好久~, 先想到的是在强连通分量中, 如果有选的就选最小的~ , 就把他当成
一个点值就是最小值(网上叫:强连通缩点)
然后剩下的图就是(如果i - j, 就不可能存在j - i)的 n个独立集合(n >= 1)
每个集合的求法自然一样, 对单个集合分析:
这个集合有可能是树, 如果是树的话, 根节点的值就是答案, 因为树根是必须联系的, 而且
联系树根之后就不必联系其他, 但是如果不是简单的树, 有可能是多颗树相交~~~,
想到这里就跪了~~, 没想到只差一点了~
如果图是多棵树相交, 那么, 入度为零的所有点就是树根, 联系所有树根就行了~~~
联系的人数自然不能再少了, 就是最少人数, 必须叫的最少人的花费自然就是最少花费~~
这个-->入度为零的点真的是非常有用的点~~~
G++ TLE C++ AC
------学习了~~~
*/
int dfn[MAX], low[MAX], v[MAX];
int index, num;
stack<int>s;
int cost[MAX], into[MAX];
int n, m;
vector<vector<int> >adj;
int nodeSet[MAX];
int minNum, minCost;
void tarjan(int node){
//cout<<node<<endl;
v[node] = 1;
s.push(node);
dfn[node] = low[node] = ++index;
int len = adj[node].size();
Rep(0, len - 1){
int pos = adj[node][i];
if(!dfn[pos]){
tarjan(pos);
low[node] = min(low[node], low[pos]);
}
else if(v[pos]){ ///,b了,v[node]
low[node] = min(low[node], dfn[pos]);
}
}
if(low[node] == dfn[node]){
num++;
while(!s.empty()){///获取的强连通分量
int t = s.top();
s.pop();
v[t] = 0;
nodeSet[t] = num;
if(t == node)
break;
}
}
}
void init(){
adj.assign(n + 1, vector<int>() );
memset(dfn, 0, sizeof(dfn));
memset(v, 0, sizeof(v));
memset(into, 0, sizeof(into));
memset(nodeSet, 0, sizeof(nodeSet));
index = num = 0;
minCost = minNum = 0;
while(!s.empty()){
s.pop();
}
}
int main(){
while(cin>>n>>m){
int a, b;
init();
Rep(1, n)cin>>cost[i];
Rep(0, m - 1){
cin>>a>>b;
adj[a].push_back(b);
}/// end input
Rep(1, n){
if(!dfn[i]){
tarjan(i);
}
}
//cout<<endl;
// cout<<num<<endl;
// Rep(1, num){
// for(int j = 1; j <= n; j++){
// if(nodeSet[j] == i)cout<<j<<" ";
// }cout<<endl;
// }
Rep(1, n){
int len = adj[i].size();
for(int j = 0; j < len; j++){
int pos = adj[i][j];
if(nodeSet[pos] != nodeSet[i]){///不在同一个强连通分量上则记录分量入度
into[nodeSet[pos]]++;
}
}
}
Rep(1, num){
if(!into[i]){
minNum++;
int minCostt = INF;
for(int j = 1; j <= n; j++){///强连通分量中取最小
if(nodeSet[j] == i){
minCostt = min(minCostt, cost[j]);
}
}
minCost += minCostt;
}
}
cout<<minNum<<" "<<minCost<<endl;
}
return 0;
}