【JZOJ 1405】电缆建设

Description

  教主上电视了,但是蔚蓝城郊区沿河的村庄却因电缆线路老化而在直播的时候停电,这让市长SP先生相当的愤怒,他决定重修所有电缆,并改日播放录像,杜绝此类情况再次发生。
  河流两旁各有n,m个村庄,每个村庄可以用二维坐标表示,其中河流一旁的村庄横坐标均为x1,河流另一旁的村庄横坐标均为x2。由于地势十分开阔,任意两个村庄可以沿坐标系直线修建一条电缆连接,长度即为两村庄的距离。要修建若干条电缆,使得任意两个村庄都可以通过若干个有电缆连接的村庄相连。
  因为修建的经费与长度成正比,SP市长当然希望所花的钱越少越好,所以他希望你来帮助他设计一套方案,使得电缆总长度最小,并告诉所需要的电缆总长度。

Solution

这题贪心的想一下,即可优化成4nlogn的DP;

当然,用DP优化一下,即可变成O(nlogn)的,先打混排序,
设两个f,g一个表示下面联通了,一个表示还未联通,互相转移;

复杂度: O(nlog(n))

Code

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cmath>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define sqr(q) ((q)*(q))
using namespace std;
typedef double db;
typedef long long LL;
const int N=600100;
int read(int &n)
{
    char ch=' ';int q=0,w=1;
    for(;(ch!='-')&&((ch<'0')||(ch>'9'));ch=getchar());
    if(ch=='-')w=-1,ch=getchar();
    for(;ch>='0' && ch<='9';ch=getchar())q=q*10+ch-48;n=q*w;return n;
}
int n,n1;
LL y[N],yy[N],b0,x1,x2;
struct qqww
{
    db v;int x,y;
}b[N*4];
int g[N*2];
db ans;
bool PX(qqww q,qqww w){return q.v<w.v;}
int gf(int q){return g[q]=(g[q]==q?q:gf(g[q]));}
int main()
{
    int q;
    read(n),read(n1),x1=read(q),x2=read(q);
    fo(i,1,n)y[i]=y[i-1]+read(q);
    fo(i,1,n1)yy[i]=yy[i-1]+read(q);
    fo(i,2,n)b[++b0].v=abs(y[i]-y[i-1]),b[b0].x=i,b[b0].y=i-1;
    fo(i,2,n1)b[++b0].v=abs(yy[i]-yy[i-1]),b[b0].x=i+n,b[b0].y=i+n-1;
    q=1;
    fo(i,1,n)if(y[i]>=yy[q])
    {
        while(q<n1&&yy[q+1]<=y[i])q++;
        b[++b0].v=sqrt(sqr(x2-x1)+sqr(yy[q]-y[i])),b[b0].x=i,b[b0].y=q+n;
    }
    q=1;
    fo(i,1,n1)if(y[q]<=yy[i])
    {
        while(q<n&&y[q+1]<=yy[i])q++;
        b[++b0].v=sqrt(sqr(x2-x1)+sqr(yy[i]-y[q])),b[b0].x=i+n,b[b0].y=q;
    }
    sort(b+1,b+1+b0,PX);
    fo(i,1,n+n1)g[i]=i;
    q=0;
    fo(i,1,b0)
    {
        if(q==n+n1-1)break;
        int x=gf(b[i].x),y=gf(b[i].y);
        if(x!=y)
        {
            q++;
            ans+=b[i].v;
            g[x]=y;
        }
    }
    printf("%.2lf\n",ans);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值