【BZOJ 4071】[apio2015]巴邻旁之桥

4071:[apio2015]巴邻旁之桥

Time limit: 2000 ms

Memory limit: 262144 KB

Description

The city of Palembang is separated by Musi River into two zones. Let’s call them zone A and zone B.

Each zone consists of exactly 1,000,000,001 buildings along the respective side of the river, conveniently numbered 0 through 1,000,000,000. The distance between every pair of adjacent buildings is 1 unit of distance. The width of the river is 1 unit of distance as well. Building i in zone A is located on exactly the opposite side of building i in zone B.

N citizens live and work in the city. Citizen i’s house is in zone Pi, building Si, while his office is in zone Qi, building Ti. If a citizen must cross the river to go from his house to his office, he must take a boat. This has been uncomfortable, so the government has decided to build at most K bridges over the river, so that the citizens can go to work by driving. Each bridge must be built exactly between two opposite buildings in the two zones. The bridges must be strictly perpendicular to the river. The bridges must not overlap each other.

Let Di be the minimum distance citizen i has to drive to go from his house to his office, after the government has built at most K bridges. Help the government build the bridges in such a way that the sum D1 + D2 + … + DN is minimized.

Input Format

The first line contains two integers K and N. Each of the next N lines contains four tokens Pi, Si, Qi, and Ti.

Output Format

A single line containing the minimum sum of the distances.

Sample Input 1

1 5

B 0 A 4

B 1 B 3

A 5 B 7

B 2 A 6

B 1 A 7

Sample Output 1

24

Sample Input 2

2 5

B 0 A 4

B 1 B 3

A 5 B 7

B 2 A 6

B 1 A 7

Sample Output 2

22

Explanation

This is the illustration for both sample inputs.

Here is one possible solution for sample input 1. The pink stripe segment denotes a bridge.

And this is a possible solution for sample input 2:

Subtasks

For each subtask,

Pi and Qi will be either a character ‘A’ or a character ‘B’.

0 ≤ Si, Ti ≤ 1,000,000,000

More than one house or office (or combination of both) can be located in the same building.

Subtask 1 (8 points)

K = 1

1 ≤ N ≤ 1,000

Subtask 2 (14 points)

K = 1

1 ≤ N ≤ 100,000

Subtask 3 (9 points)

K = 2

1 ≤ N ≤ 100

Subtask 4 (32 points)

K = 2

1 ≤ N ≤ 1,000

Subtask 5 (37 points)

K = 2

1 ≤ N ≤ 100,000

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

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

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

对于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[n]+pre<<endl;
    else
    {
        LL Ans=ans[n];
        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;
}

这道题的关键在于发现要求的是中位数,以及按照中点排序后的性质。

时间: 2024-10-06 23:11:46

【BZOJ 4071】[apio2015]巴邻旁之桥的相关文章

4071: [Apio2015]巴邻旁之桥

Description 一条东西走向的穆西河将巴邻旁市一分为二,分割成了区域 A 和区域 B. 每一块区域沿着河岸都建了恰好 1000000001 栋的建筑,每条岸边的建筑都从 0 编号到 1000000000.相邻的每对建筑相隔 1 个单位距离,河的宽度也是 1 个单位长度.区域 A 中的 i 号建筑物恰好与区域 B 中的 i 号建筑物隔河相对. 城市中有 N 个居民.第 i 个居民的房子在区域 Pi 的 Si 号建筑上,同时他的办公室坐落在 Qi 区域的 Ti 号建筑上.一个居民的房子和办公

BZOJ4071 &amp; 洛谷3644:[APIO2015]巴邻旁之桥——题解

https://www.lydsy.com/JudgeOnline/problem.php?id=4071 https://www.luogu.org/problemnew/show/P3644 一条东西走向的穆西河将巴邻旁市一分为二,分割成了区域 A 和区域 B. 每一块区域沿着河岸都建了恰好 1000000001 栋的建筑,每条岸边的建筑都从 0 编号到 1000000000.相邻的每对建筑相隔 1 个单位距离,河的宽度也是 1 个单位长度.区域 A 中的 i 号建筑物恰好与区域 B 中的

【bzoj4071】[Apio2015]巴邻旁之桥 Treap

题目描述 一条东西走向的穆西河将巴邻旁市一分为二,分割成了区域 A 和区域 B. 每一块区域沿着河岸都建了恰好 1000000001 栋的建筑,每条岸边的建筑都从 0 编号到 1000000000.相邻的每对建筑相隔 1 个单位距离,河的宽度也是 1 个单位长度.区域 A 中的 i 号建筑物恰好与区域 B 中的 i 号建筑物隔河相对. 城市中有 N 个居民.第 i 个居民的房子在区域 Pi 的 Si 号建筑上,同时他的办公室坐落在 Qi 区域的 Ti 号建筑上.一个居民的房子和办公室可能分布在河

[APIO2015]八邻旁之桥

题目描述 一条东西走向的穆西河将巴邻旁市一分为二,分割成了区域 AA 和区域 BB . 每一块区域沿着河岸都建了恰好 10000000011000000001 栋的建筑,每条岸边的建筑都从 00 编号到 10000000001000000000 .相邻的每对建筑相隔 11 个单位距离,河的宽度也是 11 个单位长度.区域 AA 中的 ii 号建筑物恰好与区域 BB 中的 ii 号建筑物隔河相对. 城市中有 NN 个居民.第 ii 个居民的房子在区域 P_iPi? 的 S_iSi? 号建筑上,同时

APIO2015 八邻旁之桥/巴邻旁之桥

题目描述: bz luogu 题解: 贪心+权值线段树. $K=1$的时候,答案为$\sum |x-l| + |x-r|$,所以所有端点排序后取中位数即可. $K=2$的时候,一定是左边的一些走左边的桥,右边的一些走右边的桥. 问题是按什么顺序排序. 答案是按线段中点排序. 原因是,对于河两岸的一对点和两座桥,选择的一定是离线段中点近的那个. 考虑如何快速计算答案,我们可以用权值线段树维护区间和与中位数.(当然也可以用平衡树) 代码: #include<cstdio> #include<

bzoj 4069~4071 APIO2015

T1 从高到底按位确定答案 A=1时f[i]表示前i个数合法的划分至少需要分出几段,时间复杂度$O(n^2log(ans))$ A>1时f[i][j]表示前i个数划分为j段是否可能合法,转移显然,时间复杂度$O(n^3log(ans)/32)$ #include<cstdio> #include<cstring> #include<bitset> typedef long long i64; int n,A,B; int f[2007]; i64 s[2007],

bzoj 4069 [Apio2015]巴厘岛的雕塑 dp

[Apio2015]巴厘岛的雕塑 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 494  Solved: 238[Submit][Status][Discuss] Description 印尼巴厘岛的公路上有许多的雕塑,我们来关注它的一条主干道. 在这条主干道上一共有 N 座雕塑,为方便起见,我们把这些雕塑从 1 到 N 连续地进行标号,其中第 i 座雕塑的年龄是 Yi 年.为了使这条路的环境更加优美,政府想把这些雕塑分成若干组,并通过在组与组之间

BZOJ 4070: [Apio2015]雅加达的摩天楼

Descrption 有\(m\)只doge,每只doge只能到\(b_i+kp_i,k\in Z\),求0号doge将信息传给1号doge的最少跳跃步数.\(n\leqslant 3\times 10^4\) Solution 分块. 将\(p\)分成大于\(\sqrt n\)和小于等于\(\sqrt n\)的两部分,然后小于的部分可以暴力建好图再连边,大于的部分直接连所有能到达的位置即可. 复杂度\(O(n\sqrt n)\). PS:UOJ上过不了Extra Text... 其实时间复杂度

bzoj 4070: [Apio2015]雅加达的摩天楼【spfa】

明明是个最短路却有网络流一样的神建图= A = 首先要是暴力建图的话最坏有O(nm)条边.所以优化建图. 考虑分块思想,设bs=sqrt(n),对于p大于bs的,直接连边即可,最多有sqrt(n)条,注意边权不全是1了,因为要从b走过去:对于p小于等于bs,先把每栋楼建sqrt个辅助点,然后这些辅助点向原点连边,其中i点的辅助点j表示i栋楼可以跳p步.这些辅助点同层之间连双向边.然后对于一只狗,直接连接b点与b点的第p辅助点即可. spfa即可 然而事实证明bs取sqrt甚至会re,直接取100