【BZOJ4071】[Apio2015]巴邻旁之桥

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

子任务

所有数据都保证: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

题解:先把不需要过桥的长度处理出来,别忘了桥的长度为1

当只有一座桥时,设位置为k,答案为∑(|ai-k|+|bi-k|),显然我们只要将ai,bi放在一起排序,取中位数就行了

当有两座桥时,我们设位置为k1,k2,那么对于第i个人,他选择kj(j=1,2)的长度为|ai-k1|+|bi-k1|,这个值有几种情况:

1.  |ai-bi|           2.  |2*kj-ai-bi|

发现他肯定会选择距离ai+bi较近的那座桥,也就是说,当我们确定了两座桥的位置后,存在一个临界值mid,使得ai+bi比mid小的都选择k1,ai+bi比mid大的都选择k2

所以我们将人按照ai+bi排序,枚举这个分界线,然后两边分别按照只有一座桥的情况处理,这就需要我们动态维护中位数+统计答案,用treap轻松搞定

注意:当可以建两座桥的时候,也要讨论只建一座桥的情况!

时间上线20s,我跑了17s,我的代码是由多丑~

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cstdlib>
using namespace std;
typedef long long ll;
const int maxn=200010;
ll N,n,m,tot,r1,r2;
ll ans,tans,sum;
char sa[5],sb[5];
ll v[maxn<<2],s[maxn<<2],cnt[maxn<<2],siz[maxn<<2];
ll key[maxn<<2],ch[maxn<<2][2];
struct node
{
ll A,B;
}p[maxn];
bool cmp(node a,node b)
{
return a.A+a.B<b.A+b.B;
}
void pushup(ll x)
{
s[x]=v[x]*cnt[x]+s[ch[x][0]]+s[ch[x][1]];
siz[x]=siz[ch[x][0]]+siz[ch[x][1]]+cnt[x];
}
void rotate(ll &x,ll d)
{
ll y=ch[x][d];
ch[x][d]=ch[y][d^1],ch[y][d^1]=x;
pushup(x),pushup(y);
x=y;
}
void insert(ll &x,ll y)
{
if(!x)
{
x=++tot;
s[x]=v[x]=y,key[x]=rand(),cnt[x]=siz[x]=1;
return ;
}
siz[x]++;
if(y==v[x])
{
cnt[x]++,s[x]+=y;
return ;
}
ll d=(y>v[x]);
insert(ch[x][d],y);
if(key[ch[x][d]]>key[x]) rotate(x,d);
pushup(x);
}
void query(ll x,ll y)
{
if(!x) return ;
if(siz[ch[x][0]]>=y)
{
sum+=v[x]*cnt[x]+s[ch[x][1]];
query(ch[x][0],y);
return ;
}
if(siz[ch[x][0]]+cnt[x]>=y)
{
sum+=s[ch[x][1]]-s[ch[x][0]];
sum+=(2*siz[ch[x][0]]+cnt[x]-2*y)*v[x];
return ;
}
sum-=s[ch[x][0]]+v[x]*cnt[x];
query(ch[x][1],y-siz[ch[x][0]]-cnt[x]);
}
void del(ll &x,ll y)
{
if(v[x]==y)
{
if(cnt[x]>1)
{
cnt[x]--,siz[x]--,s[x]-=y;
return ;
}
if(ch[x][0]*ch[x][1]==0)
{
x=ch[x][0]+ch[x][1];
return ;
}
ll d=(key[ch[x][1]]>key[ch[x][0]]);
rotate(x,d),siz[x]--,s[x]-=y;
del(ch[x][d^1],y);
return ;
}
siz[x]--,s[x]-=y;
del(ch[x][y>v[x]],y);
return ;
}
int main()
{
scanf("%d%d",&m,&N);
ll a,b,i;
for(i=1;i<=N;i++)
{
scanf("%s%lld%s%lld",sa,&a,sb,&b);
if(a>b) swap(a,b);
if(sa[0]==sb[0]) tans+=b-a;
else p[++n].A=a,p[n].B=b;
}
tans+=n;
sort(p+1,p+n+1,cmp);
if(m==1)
{
for(i=1;i<=n;i++) insert(r1,p[i].A),insert(r1,p[i].B);
query(r1,n);
printf("%lld",tans+sum);
return 0;
}
for(i=1;i<=n;i++) insert(r2,p[i].A),insert(r2,p[i].B);
sum=0; query(r2,n);
ans=tans+sum;
for(i=1;i<=n;i++)
{
del(r2,p[i].A),del(r2,p[i].B);
insert(r1,p[i].A),insert(r1,p[i].B);
sum=0;
query(r1,i),query(r2,n-i);
ans=min(ans,tans+sum);
}
printf("%lld",ans);
return 0;
}

【BZOJ4071】[Apio2015]巴邻旁之桥 Treap的更多相关文章

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

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

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

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

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

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

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

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

  5. [APIO2015]巴邻旁之桥

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

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

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

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

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

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

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

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

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

随机推荐

  1. Memcached真的过时了吗?

    Memcached真的过时了吗? 这两年Redis火得可以,Redis也常常被当作Memcached的挑战者被提到桌面上来.关于Redis与Memcached的比较更是比比皆是.然而,Redis真的在 ...

  2. CLoadScene类

    #ifndef __LOADSCENE_H__ #define __LOADSCENE_H__ #include "GameFrameHead.h" class CGameScen ...

  3. ny33 蛇形填数

    蛇形填数 时间限制:3000 ms  |  内存限制:65535 KB 难度:3 描述 在n*n方陈里填入1,2,...,n*n,要求填成蛇形.例如n=4时方陈为: 10 11 12 1 9 16 1 ...

  4. 李洪强漫谈iOS开发[C语言-053]-小结

    /* 已经学习过的C语言语法 01 基本C程序结构 int main (void) int main(int argc,char *arv){...} 02 基本语句(输入输出) 基本头文件: #in ...

  5. iOS_文件上传进度条的实现思路-AFNettworking

    iOS_文件上传进度条的实现思路-AFNettworking //要上传的文件名,在这里我使用当前日期做为文件的名称 NSString * fileName =[NSString stringWith ...

  6. Ubuntu下安装RabbbitVCS(图形化svn管理工具)- Ubuntu也有TortoiseSVN

    在Windows下用惯了TortoiseSVN这只小乌龟,到了Ubuntu下很不习惯命令行的SVN,于是经过一番寻找安装了RabbitVCS这款SVN图形化前端工具(官方网站:http://rabbi ...

  7. Qt禁止调整窗口的大小

    项目中使用的是基于对话框的程序,所以限制调整窗口大小会比较合适,下面是两种方法. 1.使用代码修改 #include "dialog.h" #include "ui_di ...

  8. js 内存泄漏

    在javascript中,我们很少去关注内存的管理.我们创建变量,使用变量,浏览器关注这些底层的细节都显得很正常. 但是当应用程序变得越来越复杂并且ajax化之后,或者用户在一个页面停留过久,我们可能 ...

  9. java 清除 bom

    参考工具  http://akini.mbnet.fi/java/unicodereader/ Utf8BomRemover 清除bom的方法 package cn.com.do1.component ...

  10. linux socket can测试

    1. Overview / What is Socket CAN -------------------------------- The socketcan package is an implem ...