Description
有一个平面,左下角是(0,0),右上角是(A,B)。
有n个平行于y轴的栅栏a1..an,表示挡在(ai,0)到(ai,B)之间。
有m个平行于x轴的栅栏b1..bn,表示挡在(0,bi)到(A,bi)之间。
这样,平面被划成了(n+1)*(m+1)块。
现在要去掉某些栅栏的一部分,使得每一块都连通。
比如原来是这样:
可以去掉后变成这样:
求最少需要去掉多少长度的栅栏使得每一块都连通。
Input
第一行四个数A,B,n,m。
A<=1000000000 ,B<=1000000000 N<=25000 M<=25000
接下来n行每行一个数表示ai
接下来m行每行一个数表示bi。
0<ai<A 0<bi<B
Output
输出一个数表示答案。
对边长排序后从小到大加边求最小生成树,一次加边加一行或一列,注意由于一部分可能已经连通,加边时要减去不需要加的边。
时间复杂度O(nlogn+mlogm+n+m)
#include<cstdio> #include<algorithm> int A,B,n,m; int ns[25005],ms[25005]; int pn=0,pm=0; long long ans=0; inline int read(){ int x=0,c=getchar(); while(c>'9'||c<'0')c=getchar(); while(c>='0'&&c<='9')x=x*10+c-'0',c=getchar(); return x; } int main(){ A=read();B=read();n=read();m=read(); ns[0]=ms[0]=0; ns[n+1]=B; ms[m+1]=A; for(int i=1;i<=n;i++)ns[i]=read(); for(int i=1;i<=m;i++)ms[i]=read(); std::sort(ns,ns+n+2); std::sort(ms,ms+m+2); for(int i=0;i<=n;i++)ns[i]=ns[i+1]-ns[i]; for(int i=0;i<=m;i++)ms[i]=ms[i+1]-ms[i]; n++;m++; std::sort(ns,ns+n); std::sort(ms,ms+m); while(pn<n&&pm<m){ if(ns[pn]<ms[pm])ans+=ns[pn]*1ll*(pm&&pn?m-pm:m-1),pn++; else ans+=ms[pm]*1ll*(pn&&pm?n-pn:n-1),pm++; } while(pn<n)ans+=ns[pn]*1ll*(pm&&pn?m-pm:m-1),pn++; while(pm<m)ans+=ms[pm]*1ll*(pn&&pm?n-pn:n-1),pm++; printf("%lld\n",ans); return 0; }