题目传送门

题目大意

有\(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. 阿里云服务器部署mongodb

    在阿里云上买了个服务器,部署mongodb遇到一些坑,解决办法也是从网上搜集而来,把零零碎碎的整理记录一下. 服务器是:Alibaba Cloud Linux 下载安装 mongodb官网下载实在是太 ...

  2. Java并发之锁升级:无锁->偏向锁->轻量级锁->重量级锁

    Java并发之锁升级:无锁->偏向锁->轻量级锁->重量级锁 对象头markword 在lock_bits为01的大前提下,只有当是否偏向锁位值为1的时候,才表明当前对象处于偏向锁定 ...

  3. Linux下Sed替换时无法解析变量

    1.问题描述 用sed替换文件中的IP时,想替换成$es_ip中的值,但是却不能解析这个变量$es_ip sed -ri 's/([0-9]{1,3}\.){3}[0-9]{1,3}/$es_ip/g ...

  4. Robot Framework(7)- DateTime 测试库常用的关键字列表

    如果你还想从头学起Robot Framework,可以看看这个系列的文章哦! https://www.cnblogs.com/poloyy/category/1770899.html 前言 所有关键字 ...

  5. javascript对象——基本对象

    1.array对象 2.Boolean包装类对象和Date对象   3.Math对象 1到100随机数 4.RegExp对象 4.1 正则规则 如: 4.2 两种创建正则对象方式 /正则表达式/    ...

  6. web、html概念快速入门

    1.C/S和B/S 总结,理论上如果硬件不考虑(带宽.(图像资源加载)显卡等),B/S可以完全替代C/S: 2.静态资源和动态资源 其中,访问时动态资源,服务器后台也会通过视图解析器转换成静态资源,因 ...

  7. MySQL实战45讲(21--25)-笔记

    21 | 为什么我只改一行的语句,锁这么多? 加锁规则里面:包含了两个"原则".两个"优化"和一个"bug". 原则 1:加锁的基本单位是 ...

  8. sticky -- position定位属性sticky值之粘性定位;

    sticky简述 sticky 是css定为新增的属性:可以说是相对定位relative和固定定位fixed的结合: 它主要用在对scroll事件的监听上,简单说在滑动过程中,某个元素的距离其父元素的 ...

  9. linux下分卷压缩,合并解压的3种方法

    我们上传东西的时候,由于文件过大而不能上传,或者不给上传,最明显的就是发邮件了,附件最大5M,有的10M.如果超过了就郁闷了.这个时候,如果能把压缩的东西,分割开来就比较爽了,windows下面我想大 ...

  10. k8s标签label

    1.给节点设置标签 一遍pod部署选择 kubectl label node 节点名 disktype=ssd kubectl label node master1 disktype=ssd 效果 [ ...