[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 的最小值。
输入输出样例
说明
【数据范围】
所有数据都保证: P_iPi 和 Q_iQi 为字符 “A” 和 “B” 中的一个, 0 \leq S_i, T_i \leq 10000000000≤Si,Ti≤1000000000 ,同一栋建筑内可能有超过 11 间房子或办公室(或二者的组合,即房子或办公室的数量同时大于等于 11 )。
子任务 1 (8 分) K = 1K=1
1 \leq N \leq 10001≤N≤1000
子任务 2 (14 分) K = 1K=1
1 \leq N \leq 1000001≤N≤100000
子任务 3 (9 分) K = 2K=2
1 \leq N \leq 1001≤N≤100
子任务 4 (32 分) K = 2K=2
1 \leq N \leq 10001≤N≤1000
子任务 5 (37 分) K = 2K=2
1 \leq N \leq 1000001≤N≤100000
在同一边的可以直接无视
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 }