题解 [BJOI2017]开车
题目大意
有\(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]开车的更多相关文章
- [BJOI2017]开车
[BJOI2017]开车 直接做要用栈 修改?难以直接维护 统计边的贡献! len*abs(pre)pre表示前缀car-stop 修改时候,整个区间的pre+1或者-1 分块,块内对pre排序并打标 ...
- noip2012开车旅行 题解
题目大意: 给出n个排成一行的城市,每个城市有一个不同的海拔.定义两个城市间的距离等于他们的高度差的绝对值,且绝对值相等的时候海拔低的距离近.有两个人轮流开车,从左往右走.A每次都选最近的,B每次都选 ...
- luoguP1081 开车旅行 题解(NOIP2012)
这道题是真滴火!(一晚上加一节信息课!) 先链接一下题目:luoguP1081 开车旅行 首先,这个预处理就极其变态,要与处理出每一个点往后走A会去哪里,B会去哪里.而且还必须O(nlogn)给它跑出 ...
- 【开车旅行】题解(NOIP2012提高组)
分析 首先我们可以发现,两个询问都可以通过一个子程序来求. 接着,如果每到一个城市再找下一个城市,显然是行不通的.所以首先先预处理从每一个城市开始,小A和小B要去的城市.预处理的方法很多,我用的是双向 ...
- 【noip2012】开车旅行
题意: 给n个点的海拔h[i](不同点海拔不同) 两点的距离为abs(h[i]-h[j]) 有a.b两人轮流开车(只能往下标大的地方开) a每次会开到里当前点第二近的点 b每次会开到离当前点最近的点( ...
- 历年NOIP选题题解汇总
联赛前上vijos板刷往年联赛题,使用在线编辑编写代码,祝我rp++. 废话不多说,挑比较有意思的记一下. 题目是按照年份排序的,最早只到了03年. 有些题目因为 我还没写/很早之前写的忘了 所以就没 ...
- 【NOIP2012】开车旅行(倍增)
题面 Description 小A 和小B决定利用假期外出旅行,他们将想去的城市从1到N 编号,且编号较小的城市在编号较大的城市的西边,已知各个城市的海拔高度互不相同,记城市 i的海拔高度为Hi,城市 ...
- 【vijos1780】【NOIP2012】开车旅行 倍增
题目描述 有\(n\)个城市,第\(i\)个城市的海拔为\(h_i\)且这\(n\)个城市的海拔互不相同.编号比较大的城市在东边.两个城市\(i,j\)之间的距离为\(|h_i-h_j|\) 小A和小 ...
- 【noip 2012】提高组Day1T3.开车旅行
Description 小A和小B决定利用假期外出旅行,他们将想去的城市从1到N编号,且编号较小的城市在编号较大的城市的西边,已知各个城市的海拔高度互不相同,记城市i 的海拔高度为Hi,城市i 和城市 ...
随机推荐
- ajax无法返回视图
$.ajax({ url:"http://localhost:8080/wb/toUpLoad", type:"post", data:formData, pr ...
- 30 道 Vue 面试题,内含详细讲解(涵盖入门到精通,自测 Vue 掌握程度)
前言 本文以前端面试官的角度出发,对 Vue 框架中一些重要的特性.框架的原理以问题的形式进行整理汇总,意在帮助作者及读者自测下 Vue 掌握的程度.本文章节结构以从易到难进行组织,建议读者按章节顺序 ...
- 接口自动化-python+requests+pytest+csv+yaml
本套代码和逻辑 是本人的劳动成果,如果有转载需要标注, 非常适合公司做项目的同学!!!小白也可以学哦! 1.项目目录 2.公共方法的封装 2.1如果不用配置文件 可以使用这个方法进行封装--但是有一 ...
- 通过 layout 探索 kratos 运行原理
创建项目 首先需要安装好对应的依赖环境,以及工具: go 下载 protoc go install google.golang.org/protobuf/cmd/protoc-gen-go@lates ...
- vue 引用高德地图
vue 引用地图之傻瓜式教程(复制粘贴即可用) npm 下载 npm install vue-amap --save main.js 代码 import AMap from 'vue-amap'; V ...
- Sentry-CLI 使用详解(2021 Sentry v21.8.x)
内容源于:https://docs.sentry.io/platforms/javascript/guides/vue/ 系列 1 分钟快速使用 Docker 上手最新版 Sentry-CLI - 创 ...
- 循环神经网络LSTM RNN回归:sin曲线预测
摘要:本篇文章将分享循环神经网络LSTM RNN如何实现回归预测. 本文分享自华为云社区<[Python人工智能] 十四.循环神经网络LSTM RNN回归案例之sin曲线预测 丨[百变AI秀]& ...
- SNMP协议之序言
最近两周公司分配一个任务:使用snmp协议做一个网管,来配置我们的产品.这可以说是我第一次听说这个协议,我问了一下周围的同事这是个什么协议,同事说"简单网络管理协议",其实这个协议 ...
- python多继承简单方法
class people(object): #建创一个人类 def __init__(self,name,age): self.name = name self.age = age def eat(s ...
- 小Z的袜子 & 莫队
莫队学习 & 小Z的袜子 引入 莫队 由莫涛巨佬提出,是一种离线算法 运用广泛 可以解决广大的离线区间询问题 莫队的历史 早在mt巨佬提出莫队之前 类似莫队的算法和莫队的思想已在Codefor ...