CF1515F. Phoenix and Earthquake

题目描述
题解

如果 Σ a i < ( n − 1 ) x \Sigma a_i < (n-1)x Σai<(n1)x ,说明不可以。

否则证明其一定可以。

假设 a 1 ≤ a 2 ≤ . . . ≤ a n a_1 \le a_2 \le ... \le a_n a1a2...an ,则如果 a n + a 1 < x a_n+a_1<x an+a1<x ,则 a 1 ≤ a 2 ≤ . . . ≤ a n < x − a 1 a_1 \le a_2 \le ... \le a_n <x-a_1 a1a2...an<xa1 ,则 Σ a i < ( n − 1 ) x − ( n − 2 ) a 1 \Sigma a_i < (n-1)x-(n-2)a_1 Σai<(n1)x(n2)a1 ,矛盾。因此我们可以每次让最大的和其相邻的任意一点合并即可。

代码
#include<bits/stdc++.h>
#define M make_pair
using namespace std;
#define LL long long
const int N=6e5+5;
int n,m,f[N],R[N],g[N],p[N],t[N];
LL a[N],X;
vector<pair<int,int>>e[N];
struct O{
	LL x;int u;
};
bool operator < (O A,O B){
	return A.x<B.x;
}
priority_queue<O>q;
int get(int x){
	return x==f[x]?x:f[x]=get(f[x]);
}
int main(){
	scanf("%d%d%lld",&n,&m,&X);
	for (int i=1;i<=n;i++)
		scanf("%lld",&a[i]),
		a[0]+=a[i],g[i]=p[i]=f[i]=i;
	for (int i=1,u,v;i<=m;i++)
		scanf("%d%d",&u,&v),
		t[u]++,t[v]++,
		e[u].push_back(M(v,i)),
		e[v].push_back(M(u,i));
	if (a[0]<X*(n-1)){puts("NO");return 0;}
	puts("YES");
	for (int i=1;i<=n;i++)
		q.push((O){a[i],i});
	while(!q.empty()){
		O u=q.top();q.pop();
		if (get(u.u)!=u.u) continue;
		int x=p[u.u];bool fl=1;
		while(fl && x){
			for (int i=t[x]-1,v;~i;i--){
				v=e[x][i].first;t[x]--;
				if (get(v)==u.u) continue;
				v=get(v);a[u.u]+=a[v]-X;
				printf("%d\n",e[x][i].second);
				R[g[u.u]]=p[v];g[u.u]=g[v];
				f[v]=u.u;fl=0;break;
			}
			if (fl) x=R[x],p[u.u]=x;
		}
		if (!fl) q.push((O){a[u.u],u.u});
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值