题意:

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 最小。
所有数据都保证:Pi 和 Qi 为字符 “A” 和 “B” 中的一个, 0≤Si,Ti≤1000000000 ,同一栋建筑内可能有超过 1 间房子或办公室(或二者的组合,即房子或办公室的数量同时大于等于 1)。
子任务 1 (8 分)K=1,1≤N≤1000
子任务 2 (14 分)K=1,1≤N≤100000
子任务 3 (9 分)K=2,1≤N≤100
子任务 4 (32 分)K=2,1≤N≤1000
子任务 5 (37 分)K=2,1≤N≤100000

Input

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

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

Output

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

题解:

首先,这题可以三分!可以三分!可以三分!

认(sui)真(bian)分(cai)析(xiang)一下可以发现,$K=1$时总花费时间随桥从左到右变化的函数是个单峰函数,$K=2$时是两个单峰函数通过某种变换之后叠加在一起,最后还是个单峰函数(然而我并不会证)

因此可以先三分第一个桥,再三分第二个桥,三分套三分的时间复杂度是$O(nlog^210^9)$的,手算大概有2.5亿,实测可以过掉前四个subtask,获得63分的好成绩(雾)

正解是权值线段树动态维护中位数。。。

$K=1$就不说了,大家都会。。。

$K=2$时有一个结论:每个人必定会走更接近$\frac{A_i+B_i}{2}$的那座桥,易得这样必定更优;

所以可以先按照$A_i+B_i$排序,左半边的人就会走左桥,右半边就走右桥;

然后就没了。。。左右各写一个数据结构,支持快速插入/删除,快速查询中位数和区间和,可以直接splay,也可以用权值线段树黑科技来做(新技能get√)

ps:所谓的黑科技就是,左右儿子哪个size大就走哪个,最后的叶节点就是中位数。。。

代码:

三分:(请木公爷来卡常啊啊啊)

 #include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<queue>
#define inf 10000000000000000
#define eps 1e-9
using namespace std;
typedef long long ll;
struct pp{
ll s1,s2,t1,t2;
}p[];
ll n,K,ans=inf,l,r,maxn=;
char sd1[],sd2[];
ll gaogao(ll k,ll kk){
ll ret=;
for(ll i=;i<=n;i++){
if(p[i].s1==p[i].s2)ret+=abs(p[i].t1-p[i].t2);
else ret+=min(abs(p[i].t1-k)+abs(p[i].t2-k)+,abs(p[i].t1-kk)+abs(p[i].t2-kk)+);
}
return ret;
}
ll gao(ll k){
if(K==){
ll ret=;
for(ll i=;i<=n;i++){
if(p[i].s1==p[i].s2)ret+=abs(p[i].t1-p[i].t2);
else ret+=abs(p[i].t1-k)+abs(p[i].t2-k)+;
}
return ret;
}
ll ret=inf,l=,r=maxn;
while(l+<=r){
ll mid=l+(r-l)/,mmid=r-(r-l)/;
if(gaogao(k,mid)<=gaogao(k,mmid))r=mmid;
else l=mid;
}
for(ll i=l;i<=r;i++){
ret=min(ret,gaogao(k,i));
}
return ret;
}
int main(){
scanf("%lld%lld",&K,&n);
for(ll i=;i<=n;i++){
scanf("%s%lld%s%lld",sd1,&p[i].t1,sd2,&p[i].t2);
p[i].s1=sd1[]-'A';
p[i].s2=sd2[]-'A';
maxn=max(maxn,max(p[i].t1,p[i].t2));
}
l=,r=maxn;
while(l+<=r){
ll mid=l+(r-l)/,mmid=r-(r-l)/;
if(gao(mid)<=gao(mmid))r=mmid;
else l=mid;
}
for(ll i=l;i<=r;i++){
ans=min(ans,gao(i));
}
printf("%lld",ans);
return ;
}

权值线段树:

 #include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<queue>
#define inf 1000000000000000
#define eps 1e-9
using namespace std;
typedef long long ll;
struct pp{
ll t1,t2;
friend bool operator <(pp a,pp b){
return a.t1+a.t2<b.t1+b.t2;
}
}p[];
struct node{
ll v,siz;
}t[][];
ll n,k,t1,t2,x1,x2,x3,x4,m1,m2,nw1=,nw2=,els=,sum=,cnt=,ans=inf,num[];
char s1[],s2[];
void updata(ll l,ll r,ll u,ll p,ll x,ll ch){
t[u][ch].siz+=x;
t[u][ch].v+=x*num[p];
if(l==r)return;
ll mid=(l+r)/;
if(p<=mid)updata(l,mid,u*,p,x,ch);
else updata(mid+,r,u*+,p,x,ch);
}
ll get(ll l,ll r,ll u,ll x,ll ch){
if(l==r)return l;
ll mid=(l+r)/;
if(x<=t[u*][ch].siz)return get(l,mid,u*,x,ch);
else return get(mid+,r,u*+,x-t[u*][ch].siz,ch);
}
ll query(ll l,ll r,ll u,ll L,ll R,ll ch,ll xx){
if(L<=l&&r<=R){
return xx?t[u][ch].v:t[u][ch].siz;
}
ll mid=(l+r)/,ret=;
if(L<=mid)ret+=query(l,mid,u*,L,R,ch,xx);
if(mid<R)ret+=query(mid+,r,u*+,L,R,ch,xx);
return ret;
}
int main(){
scanf("%lld%lld",&k,&n);
if(k==){
for(ll i=;i<=n;i++){
scanf("%s%lld%s%lld",s1,&t1,s2,&t2);
if(s1[]==s2[])els+=abs(t1-t2);
else{
num[++cnt]=t1;
num[++cnt]=t2;
}
}
ans=els+cnt/;
sort(num+,num+cnt+);
for(ll i=;i<=cnt;i++){
ans+=abs(num[i]-num[cnt/]);
}
printf("%lld",ans);
}else{
for(ll i=;i<=n;i++){
scanf("%s%lld%s%lld",s1,&t1,s2,&t2);
if(s1[]==s2[])els+=abs(t1-t2);
else{
num[++cnt]=t1;
num[++cnt]=t2;
p[++sum].t1=t1;
p[sum].t2=t2;
}
}
if(!sum)return printf("%lld\n",els),;
els+=sum;
sort(num+,num+cnt+);
cnt=unique(num+,num+cnt+)-num-;
sort(p+,p+sum+);
for(ll i=;i<=sum;i++){
nw1+=p[i].t1+p[i].t2;
p[i].t1=lower_bound(num+,num+cnt+,p[i].t1)-num;
p[i].t2=lower_bound(num+,num+cnt+,p[i].t2)-num;
updata(,cnt,,p[i].t1,,);
updata(,cnt,,p[i].t2,,);
}
for(ll i=;i<=sum;i++){
nw2+=num[p[i].t1]+num[p[i].t2];
nw1-=num[p[i].t1]+num[p[i].t2];
updata(,cnt,,p[i].t1,,);
updata(,cnt,,p[i].t1,-,);
updata(,cnt,,p[i].t2,,);
updata(,cnt,,p[i].t2,-,);
m1=get(,cnt,,i,);
m2=get(,cnt,,sum-i,);
x1=query(,cnt,,,m1,,);
x2=query(,cnt,,,m2,,);
x3=query(,cnt,,,m1,,);
x4=query(,cnt,,,m2,,);
ans=min(ans,x3*num[m1]-x1+(nw2-x1)-(i*-x3)*num[m1]+x4*num[m2]-x2+(nw1-x2)-((sum-i)*-x4)*num[m2]);
}
printf("%lld",ans+els);
}
return ;
}

【BZOJ4071】【APIO2015】巴邻旁之桥的更多相关文章

  1. [bzoj4071] [Apio2015]巴邻旁之桥

    Description 一条东西走向的穆西河将巴邻旁市一分为二,分割成了区域 A 和区域 B. 每一块区域沿着河岸都建了恰好 1000000001 栋的建筑,每条岸边的建筑都从 0 编号到 10000 ...

  2. 【BZOJ4071】[Apio2015]巴邻旁之桥 Treap

    [BZOJ4071][Apio2015]巴邻旁之桥 Description 一条东西走向的穆西河将巴邻旁市一分为二,分割成了区域 A 和区域 B. 每一块区域沿着河岸都建了恰好 1000000001 ...

  3. BZOJ4071 & 洛谷3644 & UOJ112:[APIO2015]巴邻旁之桥——题解

    https://www.lydsy.com/JudgeOnline/problem.php?id=4071 https://www.luogu.org/problemnew/show/P3644 ht ...

  4. 4071: [Apio2015]巴邻旁之桥

    Description 一条东西走向的穆西河将巴邻旁市一分为二,分割成了区域 A 和区域 B. 每一块区域沿着河岸都建了恰好 1000000001 栋的建筑,每条岸边的建筑都从 0 编号到 10000 ...

  5. [BZOJ4071][APIO2015]八邻旁之桥

    BZOJ(这题是BZOJ权限题,有权限号的就去看看吧) Luogu(良心洛谷) 题目描述 一条东西走向的穆西河将巴邻旁市一分为二,分割成了区域\(A\)和区域\(B\). 每一块区域沿着河岸都建了恰好 ...

  6. [APIO2015]巴邻旁之桥

    Bzoj权限题 luogu题面 先去掉同边的 首先k==1,即求一个点j 使\(\sum_{i\in A} |D_i - D_j| + \sum_{i\in B} |D_i - D_j|\)最小 因为 ...

  7. bzoj 4071: [Apio2015]巴邻旁之桥【splay】

    用权值线段树会容易一些并快一些,但是想复健一下splay所以打了splay 然后果然不会打了. 解题思路: 首先把家和办公室在同一侧的提出来直接加进答案里: 对于k=1,直接选所有办公室和家的中位数即 ...

  8. 洛谷 P3644 [APIO2015]八邻旁之桥 解题报告

    P3644 [APIO2015]八邻旁之桥 题目描述 一条东西走向的穆西河将巴邻旁市一分为二,分割成了区域\(A\)和区域\(B\). 每一块区域沿着河岸都建了恰好\(1000000001\)栋的建筑 ...

  9. 【BZOJ4071】八邻旁之桥(线段树)

    [BZOJ4071]八邻旁之桥(线段树) 题面 BZOJ权限题,洛谷链接 题解 既然\(k<=2\) 那么,突破口就在这里 分类讨论 ①\(k=1\) 这...不就是中位数吗.... 直接把所有 ...

  10. [APIO2015]八邻旁之桥——非旋转treap

    题目链接: [APIO2015]八邻旁之桥 对于$k=1$的情况: 对于起点和终点在同侧的直接计入答案:对于不在同侧的,可以发现答案就是所有点坐标与桥坐标的差之和+起点与终点不在同一侧的人数. 将所有 ...

随机推荐

  1. vue-router 设置默认路由

    加入 {path: '/', redirect: 'ratings'},vue 1.0版本版本使用go,但是在2.0中是用router.go(‘/ratings’);会一直刷新

  2. Type system

    Type system[edit] Main articles: Data type, Type system, and Type safety A type system defines how a ...

  3. VSCode Debug模式下各图标 含义

    按钮1:运行/继续 F5,真正的一步一步运行 按钮2:单步跳过(又叫逐过程) F10,按语句单步执行.当有函数时,不会进入函数. 按钮3:单步调试(又叫逐语句) F11:当有函数时,点击这个按钮,会进 ...

  4. 蓝桥杯_基础训练_Sine之舞

    基础练习 Sine之舞   时间限制:1.0s   内存限制:512.0MB 问题描述 最近FJ为他的奶牛们开设了数学分析课,FJ知道若要学好这门课,必须有一个好的三角函数基本功.所以他准备和奶牛们做 ...

  5. laravel报错:Unable to detect application namespace.

    使用报错:Unable to detect application namespace. 是conposer.json格式不对

  6. 利用after和before伪类实现chrome浏览器tab选项卡斜边纯css无图制作笔记

    <!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8" ...

  7. 对于 wepy 不是内部或外部命令 -- 的解决办法

    闲来没事继续研究自己之前一直未解决的问题,  就是自己笔记本安装wepy-cli,一直提示"wepy 不是内部或外部命令". 因为公司里面用的是这个框架, 想着自己在家没事的时候去 ...

  8. [TJOI2015]线性规划

    题目:洛谷P3973.BZOJ3996. 题目大意:给你n,参数b[][]和c[](里面的数均>0),要你求一个数组A[](0/1,1表示选择),已知:1. 若同时选择X和Y,获得B[x][y] ...

  9. W10子系统UBantu命令安装Redis及其启动

    W10子系统UBantu命令安装Redis及其启动 打开W10子系统UBantu 安装Redis $sudo apt-get install redis-server 启动Redis redis-se ...

  10. 【BZOJ 1297】[SCOI2009]迷路

    [链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 如果点与点之间的距离都是1的话. 那么T次方之后的矩阵上a[1][n]就是所求答案了. 但是这一题的边权可能会大于1 但最多为10 ...