首先 Yes 的必要条件是图连通且 ∑ a i ≥ ( n − 1 ) x \sum a_i\geq (n-1)x ∑ai≥(n−1)x。
发现这竟然就是充要条件。
首先一个很重要的结论:假如一开始 ∑ a i ≥ ( n − 1 ) x \sum a_i\geq (n-1)x ∑ai≥(n−1)x,那么对于之后的任意时刻肯定都满足 ∑ a i ≥ ( n − 1 ) x \sum a_i\geq (n-1)x ∑ai≥(n−1)x(连通块缩完点后)。
证明最大值+最小值一定大于等于 x x x:
-
若最大值大于等于 x x x,则证毕。
-
若最大值小于 x x x,则所有数都小于 x x x。那么若最大值+最小值小于 x x x,则它们其他所有数加起来肯定小于 ( n − 1 ) x (n-1)x (n−1)x,矛盾。
于是我们可以每次找到点权最大的那个点,并且随便选一条出边连起来。
#include<bits/stdc++.h>
#define N 300010
#define ll long long
#define fi first
#define se second
#define mk(a,b) make_pair(a,b)
using namespace std;
inline int read()
{
int x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9')
{
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
x=(x<<1)+(x<<3)+(ch^'0');
ch=getchar();
}
return x*f;
}
int n,m,x;
int fa[N];
ll val[N];
stack<pair<int,int> >e[N];
set<pair<ll,int> >s;
int find(int x)
{
return x==fa[x]?x:(fa[x]=find(fa[x]));
}
int main()
{
n=read(),m=read(),x=read();
ll sum=0;
for(int i=1;i<=n;i++) val[i]=read(),sum+=val[i];
if(sum<1ll*(n-1)*x)
{
puts("NO");
return 0;
}
puts("YES");
for(int i=1;i<=m;i++)
{
int u=read(),v=read();
e[u].push(mk(v,i)),e[v].push(mk(u,i));
}
for(int i=1;i<=n;i++)
{
fa[i]=i;
s.insert(mk(val[i],i));
}
int tot=n-1;
while(tot--)
{
auto now=*(--s.end());
int a=now.se;
while(1)
{
int b=find(e[a].top().fi),nid=e[a].top().se;
e[a].pop();
if(a==b) continue;
printf("%d\n",nid);
if(e[a].size()<e[b].size()) swap(a,b);
while(!e[b].empty())
{
e[a].push(e[b].top());
e[b].pop();
}
s.erase(mk(val[a],a));
s.erase(mk(val[b],b));
val[a]+=val[b]-x;
s.insert(mk(val[a],a));
fa[b]=a;
break;
}
}
return 0;
}