您的位置:首页 > 其它

巴邻旁之桥

2015-06-10 18:48 295 查看
Description

一条东西走向的穆西河将巴邻旁市一分为二,分割成了区域 A 和区域 B。

每一块区域沿着河岸都建了恰好 1000000001 栋的建筑,每条岸边的建筑都从 0 编号到 1000000000。相邻的每对建筑相隔 1 个单位距离,河的宽度也是 1 个单位长度。区域 A 中的 i 号建筑物恰好与区域 B 中的 i 号建筑物隔河相对。

城市中有 N 个居民。第 i 个居民的房子在区域 Pi 的 Si 号建筑上,同时他的办公室坐落在 Qi 区域的 Ti 号建筑上。一个居民的房子和办公室可能分布在河的两岸,这样他就必须要搭乘船只才能从家中去往办公室,这种情况让很多人都觉得不方便。为了使居民们可以开车去工作,政府决定建造不超过 K 座横跨河流的大桥。

由于技术上的原因,每一座桥必须刚好连接河的两岸,桥梁必须严格垂直于河流,并且桥与桥之间不能相交。当政府建造最多 K 座桥之后,设 Di 表示第 i 个居民此时开车从家里到办公室的最短距离。请帮助政府建造桥梁,使得 D1+D2+?+DN 最小。

Input

输入的第一行包含两个正整数 K 和 N,分别表示桥的上限数量和居民的数量。

接下来 N 行,每一行包含四个参数:Pi,Si,Qi 和 Ti,表示第 i 个居民的房子在区域 Pi 的 Si 号建筑上,且他的办公室位于 Qi 区域的 Ti 号建筑上。

Output

输出仅为一行,包含一个整数,表示 D1+D2+?+DN 的最小值。

Sample Input

1 5

B 0 A 4

B 1 B 3

A 5 B 7

B 2 A 6

B 1 A 7

Sample Output

24

HINT

K=1或K=2

1≤N≤100000

题解

(家和单位在同一侧的提前算好)

当把所求的计算式列出之后,可以发现最优解是所有办公室和家的位置的中位数。

对于k=1的,中位数可以直接求出。

对于k=2的,可以发现:按照每个人的家和办公室的中点排序后,一定存在一个分割点使得前缀都走左边的桥,后缀都走右边的桥(因为走靠近中点的桥不会更差)。

于是我们枚举分割点,离散化后用权值线段树动态维护两个区间的中位数求解即可。

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <map>
#include <vector>
#define pb push_back
#define M 300005
#define LL long long
using namespace std;
LL ans[M];
int size,n,k,cnt;
int ls[M],d[M];
char s1[10],s2[10];
struct data
{
int x[3];
}a[M];
struct Segtree
{
int size;
LL sum;
}t[M<<2];
int z[10];
void lisan()
{
sort(ls+1,ls+1+cnt);
size=unique(ls+1,ls+1+cnt)-ls-1;
}
int Hash(int x)
{
return lower_bound(ls+1,ls+1+size,x)-ls;
}
bool cmp(data a,data b)
{
return a.x[1]+a.x[2]<b.x[1]+b.x[2];
}
void Update(int x)
{
t[x].sum=t[x<<1].sum+t[x<<1|1].sum;
t[x].size=t[x<<1].size+t[x<<1|1].size;
}
void Build(int x,int l,int r)
{
if (l==r)
{
t[x].sum=t[x].size=0;
return;
}
int m=(l+r)>>1;
Build(x<<1,l,m);
Build(x<<1|1,m+1,r);
Update(x);
}
void Insert(int x,int l,int r,int k)
{
if (l==r)
{
t[x].sum+=d[l];
t[x].size++;
return;
}
int m=(l+r)>>1;
if (k<=m) Insert(x<<1,l,m,k);
else Insert(x<<1|1,m+1,r,k);
Update(x);
}
LL Getsum(int x,int l,int r,int cnt)
{
if (t[x].size<=cnt)
return t[x].sum;
if (l==r)
return 1LL*cnt*d[l];
int m=(l+r)>>1;
if (t[x<<1].size>=cnt) return Getsum(x<<1,l,m,cnt);
else return t[x<<1].sum+Getsum(x<<1|1,m+1,r,cnt-t[x<<1].size);
}
LL Query(LL k)
{
LL s=Getsum(1,1,size,k);
return t[1].sum-2LL*s;
}
int main()
{
scanf("%d%d",&k,&n);
LL pre=0;
int tot=0;
cnt=0;
for (int i=1;i<=n;i++)
{
int x1,x2;
scanf("%s%d%s%d",s1,&x1,s2,&x2);
if (s1[0]==s2[0])
{
pre+=abs(x1-x2);
continue;
}
pre++;
a[++tot].x[1]=x1,a[tot].x[2]=x2;
ls[++cnt]=x1,ls[++cnt]=x2;
}
if (cnt)
{
lisan();
n=tot;
for (int i=1;i<=n;i++)
d[Hash(a[i].x[1])]=a[i].x[1],d[Hash(a[i].x[2])]=a[i].x[2];
Build(1,1,size);
sort(a+1,a+1+n,cmp);
for (int i=1;i<=n;i++)
{
Insert(1,1,size,Hash(a[i].x[1]));
Insert(1,1,size,Hash(a[i].x[2]));
ans[i]=Query(i);
}
}
if (k==1)
cout<<ans
+pre<<endl;
else
{
LL Ans=ans
;
if (size)
{
Build(1,1,size);
for (int i=n;i>1;i--)
{
Insert(1,1,size,Hash(a[i].x[1]));
Insert(1,1,size,Hash(a[i].x[2]));
Ans=min(Ans,ans[i-1]+Query(n-i+1));
}
}
cout<<Ans+pre<<endl;
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: