```cpp
#include<bits/stdc++.h>
using namespace std;
const int N=2e4+5;
const int M=2.5e4+5;
const int D=15;
const int S=59059;
const int inf=1e9+7;
inline int read()
{
register int s=0;
register char c=getchar(),lc='+';
while (c<'0'||'9'<c) lc=c,c=getchar();
while ('0'<=c&&c<='9') s=s*10+c-'0',c=getchar();
return lc=='-'?-s:s;
}
void write(register int x)
{
if (x<0)
{
putchar('-');
x=-x;
}
if (x<10) putchar(x+'0');
else
{
write(x/10);
putchar(x%10+'0');
}
}
inline void print(const register int x,const register char c='\n')
{
write(x);
putchar(c);
}
struct edge
{
int to,nxt;
}e[M*2];
int head[N],cnt=0;
void add(int u,int v)
{
e[++cnt].to=v;
e[cnt].nxt=head[u];
head[u]=cnt;
}
bool vis[N];
int a[N],dep[N],Pow[D],q[N],dp[D][S];//0:选了,1:不选且没覆盖,2:不选且覆盖
inline int get(register int i,register int j)//返回i在三进制下的第j位
{
return i/Pow[dep[j]]%3;
}
inline void up(register int &x,register int y)
{
x=min(x,y);
}
void dfs(register int now)
{
register int cnt=0;
vis[now]=1;
for (register int i=head[now];i;i=e[i].nxt)
if (vis[e[i].to]&&dep[e[i].to]<dep[now])
q[++cnt]=e[i].to;//把当前节点的所有返祖边存到q中
if (dep[now]==0)
{
dp[0][0]=a[now];
dp[0][1]=0;
dp[0][2]=inf;
}//如果是根节点则不需要从父亲继承dp值
else
{
for (register int i=0;i<Pow[dep[now]+1];i++) dp[dep[now]][i]=inf;
for (register int i=0;i<Pow[dep[now]];i++)//枚举父亲的状态
{
register int No=1,Yes=i;
//No表示的是当前节点不选时,当前节点的状态
//Yes表示的是当前节点选时,当前节点到根路径上所有节点的状态
for (register int j=1;j<=cnt;j++)
{
if (get(i,q[j])==0) No=2;
//当当前节点不选时,如果返祖边有连向被选的点,那么当前节点会被覆盖
if (get(i,q[j])==1) Yes+=Pow[dep[q[j]]];
//当当前节点选时,如果返祖边连向未被选且没有被覆盖的点,那么被连向的点会被覆盖
}
up(dp[dep[now]][i+No*Pow[dep[now]]],dp[dep[now]-1][i]);
up(dp[dep[now]][Yes],dp[dep[now]-1][i]+a[now]);
}
}
for (register int i=head[now];i;i=e[i].nxt)
{
register int to=e[i].to;
if (vis[to]) continue;
dep[to]=dep[now]+1;
dfs(to);
for (register int j=0;j<Pow[dep[to]];j++)
dp[dep[now]][j]=min(dp[dep[to]][j],dp[dep[to]][j+2*Pow[dep[to]]]);
//从儿子向上更新dp值
}
}
signed main()
{
Pow[0]=1;
for (register int i=1;i<=10;i++) Pow[i]=Pow[i-1]*3;
memset(vis,0,sizeof(vis));
memset(dep,0,sizeof(dep));
register int n=read(),m=read(),ans=0;
for (register int i=1;i<=n;i++) a[i]=read();
for (register int i=1;i<=m;i++)
{
register int u=read(),v=read();
add(u,v);
add(v,u);
}
for (register int i=1;i<=n;i++)
if (!vis[i])
{
dfs(i);
ans+=min(dp[0][0],dp[0][2]);
}
print(ans);
return 0;
}
```
最后,此题卡常,记得开 O2