#include<stdio.h> #include<iostream> #include<algorithm> #include<vector> #include<cmath> using namespace std; #define N 2010 //N为最大点数 #define M 2100 //M为最大边数 int n, m;//n m 为点数和边数 struct Edge{ int from, to, nex; bool sign;//是否为桥 }edge[M<<1]; int head[N], edgenum; void add(int u, int v){//边的起点和终点 Edge E={u, v, head[u], false}; edge[edgenum] = E; head[u] = edgenum++; } int DFN[N], Low[N], Stack[N], top, Time; //Low[u]是点集{u点及以u点为根的子树} 中(所有反向弧)能指向的(离根最近的祖先v) 的DFN[v]值(即v点时间戳) int taj;//连通分支标号,从1开始 int Belong[N];//Belong[i] 表示i点属于的连通分支 bool Instack[N]; vector<int> G[N]; //标号从1开始 void tarjan(int u ,int fa){ DFN[u] = Low[u] = ++ Time ; Stack[top ++ ] = u ; Instack[u] = 1 ; for (int i = head[u] ; ~i ; i = edge[i].nex ){ int v = edge[i].to ; if(DFN[v] == -1) { tarjan(v , u) ; Low[u] = min(Low[u] ,Low[v]) ; if(DFN[u] < Low[v]) { edge[i].sign = 1;//为割桥 } } else if(Instack[v]) Low[u] = min(Low[u] ,DFN[v]) ; } if(Low[u] == DFN[u]){ int now; taj ++ ; G[taj].clear(); do{ now = Stack[-- top] ; Instack[now] = 0 ; Belong [now] = taj ; G[taj].push_back(now); }while(now != u) ; } } void tarjan_init(int all){ memset(DFN, -1, sizeof(DFN)); memset(Instack, 0, sizeof(Instack)); top = Time = taj = 0; for(int i=1;i<=all;i++)if(DFN[i]==-1 )tarjan(i, i); //注意开始点标!!! } void init(){memset(head, -1, sizeof(head)); edgenum=0;} int a[N]; int lala[N], inde[N]; #define inf 10000000 int main(){ int i,j,u,v; while(~scanf("%d %d",&n,&m)){ init(); for(i=1;i<=n;i++)scanf("%d",&a[i]); while(m--){ scanf("%d %d",&u,&v); add(u, v); } tarjan_init(n); int ans1 = 0, ans2 = 0; memset(inde, 0, sizeof(inde)); for(i = 0;i<edgenum; i++) { u = edge[i].from; v = edge[i].to; if(Belong[u] != Belong[v]) inde[ Belong[v] ] ++; } for(i = 1; i <= taj;i++) { if(inde[i] == 0) ans1++; lala[i] = inf; } for(i = 1; i <= n;i++) { int tmp = Belong[i]; if(inde[ tmp ] == 0) lala[tmp] = min(lala[tmp], a[i]); } for(i = 1; i <= taj; i++) if(lala[i] != inf) ans2 += lala[i]; printf("%d %d\n",ans1,ans2); } return 0; }