2016 NEERC, Moscow Subregional Contest K. Knights of the Old Republic(Kruskal思想)
阿新 • • 發佈:2018-10-04
std rep esp 一個點 include public fir sca code
2016 NEERC, Moscow Subregional Contest K. Knights of the Old Republic
題意:有一張圖,第i個點被占領需要ai個兵,而每個兵傳送至該點需要bi的費用。占領第i條邊需要其兩端點的兵數之和大等於ci。對於已占領的點或邊可以免費通行。因此兵達到一個點的手段有傳送和沿路走。圖上的兵可以在已占領的點、邊隨意調度。
求占領所有點的最小花費。
思路:將邊按ci進行升序排列,對於每條邊兩端點所在的連通塊進行合並,合並細節見代碼。這裏有一點值得思考:當你想打通當前這條邊時,由於排了序,你總可以默認之前那些ci小的邊已打通(因為兵可以調度)。因此,我們需要用並查集維護連通塊,以及每個連通塊中最小的傳送單價,最大的單點兵需求量,來更新花費。
#include<iostream> #include<cstdio> #include<algorithm> #define fi first #define se second using namespace std; typedef long long ll; typedef pair<ll,pair<int,int> > P; const int maxn=3e5+10; P edge[maxn]; int fa[maxn]; ll a[maxn],b[maxn],cost[maxn]; void init(int n) { for (int i=1;i<=n;++i) { fa[i]=i; cost[i]=a[i]*b[i]; } } int find(int x) { return fa[x]==x?x:fa[x]=find(fa[x]); } void unio(int x,int y,ll c) { int fx=find(x),fy=find(y); if (fx==fy) return; fa[fx]=fy; a[fy]=max(c,max(a[fy],a[fx])); b[fy]=min(b[fy],b[fx]); cost[fy]=min(cost[fy]+cost[fx],a[fy]*b[fy]); } int main() { int n,m; scanf("%d%d",&n,&m); for (int i=1;i<=n;++i) scanf("%lld%lld",&a[i],&b[i]); for (int i=0;i<m;++i) scanf("%d%d%lld",&edge[i].se.fi,&edge[i].se.se,&edge[i].fi); sort(edge,edge+m); init(n); for (int i=0;i<m;++i) { int u=edge[i].se.fi,v=edge[i].se.se,c=edge[i].fi; unio(u,v,c); } ll ans=0; for (int i=1;i<=n;++i) if (fa[i]==i) ans+=cost[i]; printf("%lld",ans); return 0; }
2016 NEERC, Moscow Subregional Contest K. Knights of the Old Republic(Kruskal思想)