傳送門
文章目錄
題意:
給你nnn個點,mmm條邊,限制xxx,每個點都有瀝青aia_iai?,定義合并兩個點即兩點之間有邊且au+av≥xa_u+a_v\ge xau?+av?≥x,合并之后的瀝青為au+av?xa_u+a_v-xau?+av??x,現在讓你輸出一種選選邊方式,選n?1n-1n?1條邊使得nnn個點聯通。
n,m<=3e5,n?1≤m,1≤x,ai≤1e9n,m<=3e5,n-1\le m,1\le x,a_i \le1e9n,m<=3e5,n?1≤m,1≤x,ai?≤1e9
思路:
首先當(n?1)?x>suma(n-1)*x>sum_a(n?1)?x>suma?的時候,顯然無解,否則一定能構造出一組解。
證明:
(1)(1)(1)當有一個點ai≥xa_i\ge xai?≥x的時候,顯然可以將他與任意一個點合并,讓后轉換成n?1n-1n?1個點的子問題。
(2)(2)(2)當所有點ai<xa_i<xai?<x的時候,那么一定有兩個點au+av≥xa_u+a_v\ge xau?+av?≥x,否則如果所有點au+av<xa_u+a_v<xau?+av?<x,那么a1+2?(a2+...+an?1)+an<(n?1)?xa_1+2*(a_2+...+a_{n-1})+a_n<(n-1)*xa1?+2?(a2?+...+an?1?)+an?<(n?1)?x,所以sum<(n?1)?xsum<(n-1)*xsum<(n?1)?x。
所以我們每次都選最大的aia_iai?,之后將他與跟他相連的且不在他集合中的點合并,用優先隊列 + 并查集可以輕松實現。
#include<cstdio>
#include<iostream>
#include<string>
#include<cstring>
#include<map>
#include<cmath>
#include<cctype>
#include<vector>
#include<set>
#include<queue>
#include<algorithm>
#include<sstream>
#include<ctime>
#include<cstdlib>
#define X first
#define Y second
#define L (u<<1)
#define R (u<<1|1)
#define pb push_back
#define mk make_pair
#define Mid (tr[u].l+tr[u].r>>1)
#define Len(u) (tr[u].r-tr[u].l+1)
#define random(a,b) ((a)+rand()%((b)-(a)+1))
#define db puts("---")
using namespace std
;
typedef long long LL
;
typedef unsigned long long ULL
;
typedef pair
<LL
,int> PII
;const int N
=1000010,mod
=1e9+7,INF
=0x3f3f3f3f;
const double eps
=1e-6;int n
,m
,x
;
LL p
[N
],a
[N
];
vector
<vector
<PII
>>v(N
);int find(int x
)
{return x
==p
[x
]? x
:p
[x
]=find(p
[x
]);
}int main()
{
LL sum
=0;scanf("%d%d%d",&n
,&m
,&x
);for(int i
=1;i
<=n
;i
++) scanf("%lld",&a
[i
]),sum
+=a
[i
],p
[i
]=i
;for(int i
=1;i
<=m
;i
++){int a
,b
; scanf("%d%d",&a
,&b
);v
[a
].emplace_back(b
,i
); v
[b
].emplace_back(a
,i
);}if(sum
<1ll*(n
-1)*x
) { puts("NO"); return 0; }priority_queue
<PII
>q
;for(int i
=1;i
<=n
;i
++) q
.push({a
[i
],i
});puts("YES");for(int i
=1;i
<=n
-1;i
++){PII t
=q
.top(); q
.pop();int u
=t
.Y
;while(u
!=find(u
)){t
=q
.top(); q
.pop();u
=t
.Y
;}while(u
==find(v
[u
].back().X
)&&v
[u
].size()) v
[u
].pop_back();printf("%d\n",v
[u
].back().Y
);int vv
=find(v
[u
].back().X
);a
[u
]+=a
[vv
]-x
;q
.push({a
[u
],u
});p
[vv
]=u
;if(v
[u
].size()<v
[vv
].size()) {swap(v
[u
],v
[vv
]);}v
[u
].insert(v
[u
].end(),v
[vv
].begin(),v
[vv
].end());v
[vv
].clear();}return 0;
}
總結
以上是生活随笔為你收集整理的Codeforces Global Round 14 F. Phoenix and Earthquake 思维 + 并查集的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。