题目传送门

题目大意

有\(n\)个汽车和\(n\)个加油站,坐标分别为\(a_{1,2,...,n}\)和\(b_{1,2,...,n}\)。每辆汽车会到一个加油站,求出最小移动距离之和。有\(m\)次修改,每次将某辆汽车的坐标进行修改,求出修改后的最小移动距离之和。

\(n,m\le 5\times 10^4\)

思路

看到题解都写得比较繁杂,这里提供一种不是那么繁杂的方法。借鉴了Miracle的博客shadowice1984的题解

首先,不难看出对于某一条边,它的贡献为它的长度乘上\(|sum|\),其中,\(sum\)就是在它之前的汽车-在它之前的加油站。它的意义就是因为要一一对应,所以差的数量就需要通过移动填补,而移动就需要经过该边。

而我们的修改操作,相当于删掉一个点再加入一个点。考虑加入一个点,那我们就相当于把后面的点的\(sum+1\)。但是因为贡献里面带有绝对值,所以我们不能直接搞,对于这种问题我们一个常用的解决方法就是直接分块。对于某个块,我们可以按\(sum\)大小排序,二分找到分界点,然后分别考虑\(sum< 0\)和\(sum\ge0\)的情况即可。删掉一个点同理。

于是,我们就可以在\(\Theta(n\sqrt n(\log \sqrt n))\)的时间复杂度内解决这个问题。

\(\texttt{Code}\)

#include <bits/stdc++.h>
using namespace std; #define Abs(x) ((x)>=0?(x):-(x))
#define Int register int
#define ll long long
#define MAXN 200005
#define MAXM 455 template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;}
template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);}
template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');} int n,m,un,a[MAXN],b[MAXN],tmp[MAXN]; struct Query{
int x,y;
}q[MAXN]; ll ans;
int siz,val[MAXN],sum[MAXN],bel[MAXN],ord[MAXN],col[MAXM],cor[MAXM],tag[MAXN],sval[MAXN]; bool cmp (int a,int b){return sum[a] < sum[b];} void rebuild (int x){
sort (ord + col[x],ord + cor[x] + 1,cmp);
sval[col[x]] = val[ord[col[x]]];for (Int i = col[x] + 1;i <= cor[x];++ i) sval[i] = sval[i - 1] + val[ord[i]];
} void init (){
for (Int i = 1;i <= n;++ i) sum[a[i]] ++,sum[b[i]] --;
for (Int i = 1;i <= un;++ i){
if (i < un) val[i] = tmp[i + 1] - tmp[i];
sum[i] += sum[i - 1],ans += 1ll * Abs (sum[i]) * val[i];
}
siz = ceil (sqrt (un));
for (Int i = 1;i <= un;++ i){
bel[i] = (i - 1) / siz + 1,ord[i] = i;
if (!col[bel[i]]) col[bel[i]] = i;
cor[bel[i]] = i;
}
for (Int i = 1;i <= bel[un];++ i) rebuild (i);
} void ins (int x){
for (Int i = x;i <= cor[bel[x]];++ i){
ans += 1ll * val[i] * (sum[i] + tag[bel[x]] >= 0 ? 1 : -1);//注意:三目运算符优先级比加减乘除低
sum[i] ++;
}
rebuild (bel[x]);
for (Int i = bel[x] + 1;i <= bel[un];++ i){
int l = col[i],r = cor[i],res = -1;
while (l <= r){
int mid = (l + r) >> 1;
if (sum[ord[mid]] + tag[i] >= 0) res = mid,r = mid - 1;
else l = mid + 1;
}
if (res == -1) ans -= sval[cor[i]];
else if (res == col[i]) ans += sval[cor[i]];
else{
ans -= sval[res - 1];
ans += sval[cor[i]] - sval[res - 1];
}
tag[i] ++;
}
} void del (int x){
for (Int i = x;i <= cor[bel[x]];++ i){
ans += 1ll * val[i] * (sum[i] + tag[bel[x]] <= 0 ? 1 : -1);//注意:三目运算符优先级比加减乘除低
sum[i] --;
}
rebuild (bel[x]);
for (Int i = bel[x] + 1;i <= bel[un];++ i){
int l = col[i],r = cor[i],res = -1;
while (l <= r){
int mid = (l + r) >> 1;
if (sum[ord[mid]] + tag[i] <= 0) res = mid,l = mid + 1;
else r = mid - 1;
}
if (res == -1) ans -= sval[cor[i]];
else if (res == cor[i]) ans += sval[cor[i]];
else{
ans += sval[res];
ans -= sval[cor[i]] - sval[res];
}
tag[i] --;
}
} signed main(){
read (n);
for (Int i = 1;i <= n;++ i) read (a[i]),tmp[++ un] = a[i];
for (Int i = 1;i <= n;++ i) read (b[i]),tmp[++ un] = b[i];
read (m);for (Int i = 1;i <= m;++ i) read (q[i].x,q[i].y),tmp[++ un] = q[i].y;
sort (tmp + 1,tmp + un + 1),un = unique (tmp + 1,tmp + un + 1) - tmp - 1;
for (Int i = 1;i <= n;++ i) a[i] = lower_bound (tmp + 1,tmp + un + 1,a[i]) - tmp,b[i] = lower_bound (tmp + 1,tmp + un + 1,b[i]) - tmp;
for (Int i = 1;i <= m;++ i) q[i].y = lower_bound (tmp + 1,tmp + un + 1,q[i].y) - tmp;
init (),write (ans),putchar ('\n');
for (Int i = 1,x,y;i <= m;++ i){
x = q[i].x,y = q[i].y;
del (a[x]),ins (a[x] = y);
write (ans),putchar ('\n');
}
return 0;
}

题解 [BJOI2017]开车的更多相关文章

  1. [BJOI2017]开车

    [BJOI2017]开车 直接做要用栈 修改?难以直接维护 统计边的贡献! len*abs(pre)pre表示前缀car-stop 修改时候,整个区间的pre+1或者-1 分块,块内对pre排序并打标 ...

  2. noip2012开车旅行 题解

    题目大意: 给出n个排成一行的城市,每个城市有一个不同的海拔.定义两个城市间的距离等于他们的高度差的绝对值,且绝对值相等的时候海拔低的距离近.有两个人轮流开车,从左往右走.A每次都选最近的,B每次都选 ...

  3. luoguP1081 开车旅行 题解(NOIP2012)

    这道题是真滴火!(一晚上加一节信息课!) 先链接一下题目:luoguP1081 开车旅行 首先,这个预处理就极其变态,要与处理出每一个点往后走A会去哪里,B会去哪里.而且还必须O(nlogn)给它跑出 ...

  4. 【开车旅行】题解(NOIP2012提高组)

    分析 首先我们可以发现,两个询问都可以通过一个子程序来求. 接着,如果每到一个城市再找下一个城市,显然是行不通的.所以首先先预处理从每一个城市开始,小A和小B要去的城市.预处理的方法很多,我用的是双向 ...

  5. 【noip2012】开车旅行

    题意: 给n个点的海拔h[i](不同点海拔不同) 两点的距离为abs(h[i]-h[j]) 有a.b两人轮流开车(只能往下标大的地方开) a每次会开到里当前点第二近的点 b每次会开到离当前点最近的点( ...

  6. 历年NOIP选题题解汇总

    联赛前上vijos板刷往年联赛题,使用在线编辑编写代码,祝我rp++. 废话不多说,挑比较有意思的记一下. 题目是按照年份排序的,最早只到了03年. 有些题目因为 我还没写/很早之前写的忘了 所以就没 ...

  7. 【NOIP2012】开车旅行(倍增)

    题面 Description 小A 和小B决定利用假期外出旅行,他们将想去的城市从1到N 编号,且编号较小的城市在编号较大的城市的西边,已知各个城市的海拔高度互不相同,记城市 i的海拔高度为Hi,城市 ...

  8. 【vijos1780】【NOIP2012】开车旅行 倍增

    题目描述 有\(n\)个城市,第\(i\)个城市的海拔为\(h_i\)且这\(n\)个城市的海拔互不相同.编号比较大的城市在东边.两个城市\(i,j\)之间的距离为\(|h_i-h_j|\) 小A和小 ...

  9. 【noip 2012】提高组Day1T3.开车旅行

    Description 小A和小B决定利用假期外出旅行,他们将想去的城市从1到N编号,且编号较小的城市在编号较大的城市的西边,已知各个城市的海拔高度互不相同,记城市i 的海拔高度为Hi,城市i 和城市 ...

随机推荐

  1. flex布局中flex属性运用在随机发红包的算法上

    flex布局是现在前端基本上都会运用的一种布局,基本上用到比较多的是父元素设置display:flex,两个子元素,一个设置固定宽度,另一个设置为flex:1(这里都指flex-direction为r ...

  2. 证明n个正数的算术平均数不小于它们的几何平均数

  3. Spring事物入门简介及AOP陷阱分析

    转载请注明出处: https://www.cnblogs.com/qnlcy/p/15237377.html 一.事务的定义 事务(Transaction),是指访问并可能更新数据库中各种数据项的一个 ...

  4. Pytest系列(12)- 测试结果生成HTML报告插件之pytest-html的详细使用

    如果你还想从头学起Pytest,可以看看这个系列的文章哦! https://www.cnblogs.com/poloyy/category/1690628.html 环境前提 Python3.6+ 安 ...

  5. Docker(34)- 如何修改 docker 容器的目录映射

    如果你还想从头学起 Docker,可以看看这个系列的文章哦! https://www.cnblogs.com/poloyy/category/1870863.html 问题背景 docker run ...

  6. Docker(36)- docker run 的流程和原理

    背景 目前项目组上, Docker 用的非常重,所有微服务都是通过 docker 来部署的 所以不能仅仅会命令,还得会一些原理的东西,特此补一篇基础点的,后面再更加深入一些 docker 原理 本篇学 ...

  7. python3 用multiprocessing模块传递多个参数

    from datetime import datetime from time import sleep import numpy as np import multiprocessing # fro ...

  8. C#提取程序的图标

    需要添加对System.Management.dll的引用  ,并且不要忘记导入下面的名称空间. using System.Management; 将ListView和  ImageList控件从可视 ...

  9. 推荐一款编程字体:Iosevka

    最近发现一款很好用的编程字体:Iosevka.它是一款现代化的编程字体集合,除了等宽.oO0 iIl1明显区分等基本特性外,还有很多非常现代的特性,比如: 多种风格:有非常多的字形可供选择,衬线/非衬 ...

  10. Linux内核下包过滤框架——iptables&netfilter

    iptables & netfilter 1.简介 netfilter/iptables(下文中简称为iptables)组成Linux内核下的包过滤防火墙,完成封包过滤.封包重定向和网络地址转 ...