题目传送门

题目大意

有\(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. 初步测试VS2017+Win10IoT,基于World Map of Makers

    测试World Map of Makers Demo,创建一个简单的internet连接应用程序来查询web API的状态(目测是一个延时时间),并使用该信息切换LED. 官方仓库的Solution是 ...

  2. MySQL-SQL基础-查询2

    mysql> create table customer(mid char(5) primary key,th date,sex char(1) default '0'); Query OK, ...

  3. python--接口自动化经常用到的pytest框架

    pytest常用的方法和原理 1.pytest的原理 pytest插件基于pluggy模块:pluggy有三个重要概念:HookspecMarker(用来定义hook函数),HookimplMarke ...

  4. 一种封装Retrofit的方法,可以自动解析Gson,回避Method return type must not include a type variable or wildcard: retrofit2.Call<T>的问题

    封装目的:屏蔽底层实现,提供统一接口,并支持Gson自动转化 最初封装: //请求方法 interface RequestListener { interface PostListener { @PO ...

  5. JavaScript高级程序设计读书笔记之JSON

    JSON(JavaScript Object Notation)JavaScript对象表示法.JSON是JavaScript的一个严格的子集,利用了JavaScript中的一些模式来表示结构化数据. ...

  6. Redis的持久化机制与内存管理机制

    1.概述 Redis的持久化机制有两种:RDB 和 AOF ,这两种机制有什么区别?正式环境应该采用哪种机制? 我们的服务器内存资源是有限的,如果内存被Redis的缓存占满了怎么办?这就要看Redis ...

  7. python库--sklearn--流程图

  8. 在windows中给git修改默认的编辑器为sublime

    首先,需要配置sublime的为环境变量,这是为了让git能通过命令调用sublime.也可以写一个.bat脚本.然后,让git调用bat脚本也可以 配置环境变量path到subl.exe的目录 脚本 ...

  9. Java Web下MySQL数据库的增删改查(一)

    以图书管理系统举例(jsp+servlet+bean) 1.数据库的连接 package db; import java.sql.Connection; import java.sql.DriverM ...

  10. rabbitmqctl 命令行管理工具

    1. 用户管理 用户管理包括增加用户,删除用户,查看用户列表,修改用户密码. (1) 新增一个用户 rabbitmqctl add_user Username Password (2) 删除一个用户 ...