题目传送门

题目大意

有\(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. Go版本管理--依赖包存储

    目录 1. 简介 2. GOPATH 依赖包存储 3.GOMODULE 依赖包存储 4.包名大小写敏感问题 1. 简介 GOPATH模式下,依赖包存储在$GOPATH/src,该目录下只保存特定依赖包 ...

  2. WIN10 64bit + QT5.10.0(MinGW3.5.0) + OpenCV3.4.1 无痛安装、配置

    安装QT和配置MinGW 官方下载qt-opensource-windows-x86-5.10.0.exe 正常步骤安装QT5.10.0,安装过程选择自带的MinGW3.5.0编译器即可. 打开QtC ...

  3. python类、继承

    Python 是一种面向对象的编程语言.Python 中的几乎所有东西都是对象,拥有属性和方法.类(Class)类似对象构造函数,或者是用于创建对象的"蓝图". 一.python ...

  4. github搜索技巧小结

    欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...

  5. Appium自动化(8) - 可定位的控件属性

    如果你还想从头学起Appium,可以看看这个系列的文章哦! https://www.cnblogs.com/poloyy/category/1693896.html 前言 在前面几篇文章可以看到,一个 ...

  6. python库--jieba(中文分词)

    import jieba 精确模式,试图将句子最精确地切开,适合文本分析:全模式,把句子中所有的可以成词的词语都扫描出来, 速度非常快,但是不能解决歧义:搜索引擎模式,在精确模式的基础上,对长词再次切 ...

  7. Axis <=1.4 RCE 复现

    1.环境搭建 在idea 上新建项目,然后用tomcat运行即可 2.漏洞复现 2.1 freemarker.template.utility.Execute 如果项目里面没有freemarker 就 ...

  8. Git 初识和使用

    目录 目录 目录 概念 工作区/暂存区/版本库 master 版本号 常见命令 环境搭建 Linux 下 Git 和 GitHub 环境的搭建 Git 本地操作 本地仓库的创建和使用 查看信息 查看状 ...

  9. RabbitMQie消息列队整理

    使用方法过程,这儿只做了windows平台教程 先安装Erlang 编程软件,然后设置环境变量,在安装RabbimMQ ,这儿我下载了一个版本不行,后来换了最新版就好了,以后在使用过程 中如果有问题 ...

  10. 学习PHP弱引用的知识

    之前的文章中,我们已经学习过引用和引用传值相关的知识.我们知道,PHP 中没有纯引用(指针),不管是对象,还是用引用符号 & 赋值的变量,都是对一个符号表的引用.而今天,我们要学习的是另一种引 ...