[APIO2015]八邻旁之桥

题目描述

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

每一块区域沿着河岸都建了恰好 10000000011000000001 栋的建筑,每条岸边的建筑都从 00 编号到 10000000001000000000 。相邻的每对建筑相隔 11 个单位距离,河的宽度也是 11 个单位长度。区域 AA 中的 ii 号建筑物恰好与区域 BB 中的 ii 号建筑物隔河相对。

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

由于技术上的原因,每一座桥必须刚好连接河的两岸,桥梁必须严格垂直于河流,并且桥与桥之间不能相交。

当政府建造最多 KK 座桥之后,设 D_iDi 表示第 ii 个居民此时开车从家里到办公室的最短距离。请帮助政府建造桥梁,使得 D_1 + D_2 + \cdots + D_ND1+D2++DN 最小。

输入输出格式

输入格式:

 

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

接下来 NN 行,每一行包含四个参数: P_i, S_i, Q_iPi,Si,Qi 和 T_iTi ,表示第 ii 个居民的房子在区域 P_iPi 的 S_iSi 号建筑上,且他的办公室位于 Q_iQi 区域的 T_iTi 号建筑上。

 

输出格式:

 

输出仅为一行,包含一个整数,表示 D_1 + D_2 + \cdots + D_ND1+D2++DN 的最小值。

 

输入输出样例

输入样例#1: 复制
1 5
B 0 A 4
B 1 B 3
A 5 B 7
B 2 A 6
B 1 A 7
输出样例#1: 复制
24
输入样例#2: 复制
2 5
B 0 A 4
B 1 B 3
A 5 B 7
B 2 A 6
B 1 A 7
输出样例#2: 复制
22

说明

【数据范围】

所有数据都保证: P_iPi 和 Q_iQi 为字符 “A” 和 “B” 中的一个, 0 \leq S_i, T_i \leq 10000000000Si,Ti1000000000 ,同一栋建筑内可能有超过 11 间房子或办公室(或二者的组合,即房子或办公室的数量同时大于等于 11 )。

子任务 1 (8 分) K = 1K=1

1 \leq N \leq 10001N1000

子任务 2 (14 分) K = 1K=1

1 \leq N \leq 1000001N100000

子任务 3 (9 分) K = 2K=2

1 \leq N \leq 1001N100

子任务 4 (32 分) K = 2K=2

1 \leq N \leq 10001N1000

子任务 5 (37 分) K = 2K=2

1 \leq N \leq 1000001N100000

在同一边的可以直接无视

k=1时

取所有的居民的(家坐标+公司坐标)/2的所有坐标的正中间建一座桥,使所有居民到的距离最小。

 

k=2时

取每个线段的中点,如果靠近左边的桥,就往左边过桥,否则往右边过桥。

这样的话,先把线段按l+r排序,如果枚举一个分割线,左右两边分别转换成为K=1的情况了

用离散+线段树查找中位数

f[i]表示1~i中的居民走一座桥

然后从后往前再算一次,答案是min(f[i]+ans(i+1~n))

如果是k=1直接输出f[n]

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 #include<cmath>
  6 using namespace std;
  7 typedef long long lol;
  8 struct ZYYS
  9 {
 10   int l,r;
 11 }d[200001];
 12 lol p[400001];
 13 int cnt,tot,n,k;
 14 lol s[1600001],c[1600001],flag,delta,f[200001],ans;
 15 char s1[6],s2[6];
 16 bool cmp(ZYYS a,ZYYS b)
 17 {
 18   return a.l+a.r<b.l+b.r;
 19 }
 20 void pushup(int rt)
 21 {
 22   s[rt]=(s[rt*2]+s[rt*2+1]);
 23   c[rt]=(c[rt*2]+c[rt*2+1]);
 24 }
 25 void update(int rt,int l,int r,int x,lol d)
 26 {
 27   if (l==r)
 28     {
 29       c[rt]++;
 30       s[rt]+=d;
 31       return;
 32     }
 33   int mid=(l+r)/2;
 34   if (x<=mid) update(rt<<1,l,mid,x,d);
 35   else update(rt<<1|1,mid+1,r,x,d);
 36   pushup(rt);
 37 }
 38 lol query(int rt,int l,int r,int x)
 39 {
 40   if (l==r)
 41     {
 42       return p[l]*x;
 43     }
 44   int mid=(l+r)/2;
 45   if (c[rt*2]<x) return s[rt*2]+query(rt*2+1,mid+1,r,x-c[rt*2]);
 46   else return query(rt*2,l,mid,x);
 47 }
 48 lol cal(int x)
 49 {
 50   lol tmp=query(1,1,tot,x);
 51   return s[1]-2*tmp;
 52 }
 53 int main()
 54 {int x,y,i;
 55   cin>>k>>n;
 56   for (i=1;i<=n;i++)
 57     {
 58       scanf("%s%d%s%d",s1,&x,s2,&y);
 59       if (x>y) swap(x,y);
 60       if (s1[0]==s2[0])
 61     delta+=y-x;
 62       else
 63     {
 64       delta++;
 65       d[++cnt]=(ZYYS){x,y};
 66       p[++tot]=x;p[++tot]=y;
 67     }
 68     }
 69   n=cnt;
 70   sort(p+1,p+tot+1);
 71   cnt=unique(p+1,p+tot+1)-p-1;
 72   tot=cnt;
 73   sort(d+1,d+n+1,cmp);
 74   for (i=1;i<=n;i++)
 75     {
 76       d[i].l=lower_bound(p+1,p+tot+1,d[i].l)-p;
 77       d[i].r=lower_bound(p+1,p+tot+1,d[i].r)-p;
 78     }
 79   for (i=1;i<=n;i++)
 80     {
 81       update(1,1,tot,d[i].l,p[d[i].l]);
 82       update(1,1,tot,d[i].r,p[d[i].r]);
 83       f[i]=cal(i);
 84     }
 85   if (k==1)
 86     {
 87       cout<<f[n]+delta;
 88       return 0;
 89     }
 90   memset(s,0,sizeof(s));
 91   memset(c,0,sizeof(c));
 92   ans=f[n];
 93   for (i=n;i>=1;i--)
 94     {
 95       update(1,1,tot,d[i].l,p[d[i].l]);
 96       update(1,1,tot,d[i].r,p[d[i].r]);
 97       ans=min(ans,f[i-1]+cal(n-i+1));
 98     }
 99   cout<<ans+delta;
100 }

 

posted @ 2018-04-22 19:00  Z-Y-Y-S  阅读(478)  评论(0编辑  收藏  举报