来自FallDream的博客,未经允许,请勿转载,谢谢。


你有n辆车,分别a1, a2, ..., an位置和n个加油站,分别在b1, b2, ... ,bn 。每个加油站只能支持一辆车的加油,所以你要把这些车开到不同的加油站加油。一个车从x位置开到y位置的代价为 |x-y| ,问如何安排车辆,使得代价之和最小。同时你有q个操作,每次操作会修改第i辆车的位置到x,你要回答每次修改操作之后最优安排方案的总代价。
 
n,m<=50000
 
首先排序之后一一匹配肯定是最优的。
把点离散之后,车看作1,加油站看作-1,求前缀和。对于离散后的每个点,如果它的前缀和不为0,那么显然有些车/加油站不能匹配,产生的代价是前缀和的绝对值乘以这个点到下个点的距离。
考虑分块维护这东西。对离散的点分根号个块,每一块都自己做一遍,处理出这个块在块之前的点前缀和取不同的值时会产生的代价。由于一个块自己的前缀和不超过根号n,所以只处理前缀和在正负根号n以内的即可,大于根号n或者小于负根号n的,额外代价加入的值相同。处理这个代价可以差分再差分,最后前缀和再前缀和,具体实现可以见代码,处理一个块复杂度$O(\sqrt{n})$。
然后对于修改操作,中间的整块移动一下重新统计答案,两遍的块重构即可。
复杂度$O(n\sqrt{n})$
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#define getchar() (*S++)
#define pa pair<int,int>
#define ll long long
#define MN 50000
#define MB 400
char B[<<],*S=B;
using namespace std;
inline int read()
{
int x = , f = ; char ch = getchar();
while(ch < '' || ch > ''){ if(ch == '-') f = -; ch = getchar();}
while(ch >= '' && ch <= ''){x = x * + ch - '';ch = getchar();}
return x * f;
}
long long Ans,ans[MB+],F[MB+][MB*+],f[MB+][MB*+];
int n,m,l[MN*+],cnt=,pos[MB+],a[MN+],block[MN*+],v[MN*+];
int s[MN*+],b[MN+],tot=,size;
struct ques{int x,y;}q[MN+];
inline int abs(int x){return x<?-x:x;}
void Move(int x,int y)
{
Ans-=ans[x];
if(abs(y)<=MB) Ans+=(ans[x]=F[x][MB+y]);
else
{
if(y>MB) Ans+=(ans[x]=F[x][MB<<]+1LL*(y-MB)*f[x][MB<<]);
if(y<MB) Ans+=(ans[x]=F[x][]+1LL*(MB-y)*f[x][]);
}
} void Build(int x)
{
int W=;
for(int i=;i<=MB<<;++i) f[x][i]=F[x][i]=;
for(int i=(x-)*size+;block[i]==x;++i)
{
F[x][MB]+=1LL*v[i]*abs(W+=s[i]);
if(!W) f[x][+MB]+=v[i],f[x][MB-]+=v[i];
if(W>) f[x][MB+]+=v[i],W<MB?(f[x][MB-W-]+=v[i]<<):,f[x][MB-]-=v[i];
if(W<) f[x][MB+]-=v[i],f[x][MB-W+]+=v[i]<<,f[x][MB-]+=v[i];
}
for(int i=;i<=MB;++i)
F[x][MB+i]=F[x][MB+i-]+(f[x][MB+i]+=f[x][MB+i-]),
F[x][MB-i]=F[x][MB-i+]+(f[x][MB-i]+=f[x][MB-i+]);
Move(x,pos[x]);
} int main()
{
fread(B,,<<,stdin);
n=read();
for(int i=;i<=n;++i) a[i]=l[++cnt]=read();
for(int i=;i<=n;++i) b[i]=l[++cnt]=read();
m=read();
for(int i=;i<=m;++i) q[i].x=read(),q[i].y=l[++cnt]=read();
sort(l+,l+cnt+);
for(int i=;i<=cnt;++i) if(l[i]!=l[i-]) l[++tot]=l[i];
for(int i=;i<tot;++i) v[i]=l[i+]-l[i];
size=sqrt(tot);
for(int i=;i<=n;++i)
a[i]=lower_bound(l+,l+tot+,a[i])-l,
b[i]=lower_bound(l+,l+tot+,b[i])-l,
++s[a[i]],--s[b[i]];
for(int i=;i<=tot;++i) block[i]=(i-)/size+;
for(int i=,w=;i<=block[tot];++i)
{
pos[i]=w;Build(i);
for(int j=(i-)*size+;block[j]==i;++j) w+=s[j];
}
printf("%lld\n",Ans);
for(int i=;i<=m;++i)
{
q[i].y=lower_bound(l+,l+tot+,q[i].y)-l;
if(q[i].y!=a[q[i].x])
{
--s[a[q[i].x]];++s[q[i].y];
if(block[q[i].y]==block[a[q[i].x]])
Build(block[q[i].y]);
else
{
int From=min(block[a[q[i].x]],block[q[i].y]),
To=max(block[a[q[i].x]],block[q[i].y]);
for(int j=From+;j<To;++j)
Move(j,pos[j]+=(q[i].y>a[q[i].x]?-:));
if(a[q[i].x]>q[i].y) ++pos[block[a[q[i].x]]];
else --pos[block[q[i].y]];
Build(block[q[i].y]);Build(block[a[q[i].x]]);
}
}
a[q[i].x]=q[i].y;printf("%lld\n",Ans);
}
return ;
}

[bzoj4908][BeiJing2017]开车的更多相关文章

  1. 【BZOJ4908】[BeiJing2017]开车 分块

    [BZOJ4908][BeiJing2017]开车 Description 你有n辆车,分别a1, a2, ..., an位置和n个加油站,分别在b1, b2, ... ,bn .每个加油站只能支持一 ...

  2. [BZOJ]4908: [BeiJing2017]开车

    Time Limit: 30 Sec  Memory Limit: 256 MB Description 你有n辆车,分别a1, a2, ..., an位置和n个加油站,分别在b1, b2, ... ...

  3. vijos P1780 【NOIP2012】 开车旅行

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

  4. [NOIP2012] 提高组 洛谷P1081 开车旅行

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

  5. 豆制品厂开车超市送货智能手持PDA POS打票机-手持票据打印机

    豆制品厂开车拉着豆腐到某一个超市送货,到达后秤出斤数后就用票据打印机开单 能直接开单,单子一式两份,一张给客户一张留底,到月底时客户要根据客户的量返点的,单子统计.能现场开单,单子上显示哪个超市,豆制 ...

  6. 在包a中编写一个类Father,具有属性:年龄(私有)、姓名(公有); 具有功能:工作(公有)、开车(公有)。 在包a中编写一个子类Son,具有属性:年龄(受保护的)、姓名; 具有功能:玩(私有)、学习(公有)。 最后在包b中编写主类Test,在主类的main方法中测试类Father与类Son。

    package a; public class Father { public String name; private int age; public Father(String name) { t ...

  7. 【noip2012】开车旅行

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

  8. 【NOIP 2012 开车旅行】***

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

  9. javascript 老王开车去东北

    [Decode error - output not utf-8] 魔女 飞 奔驰 去 华南 [Finished in 1.1s] 需要变化的对象进行隔离.正是编程的乐趣之处 /** * by Jac ...

随机推荐

  1. js 选择图片生成base64数据

    <!doctype html> <html> <head> <meta charset="utf-8"> <meta http ...

  2. Codeforces 193 D. Two Segments

    http://codeforces.com/contest/193/problem/D 题意: 给一个1~n的排列,在这个排列中选出两段区间,求使选出的元素排序后构成公差为1的等差数列的方案数. 换个 ...

  3. mysql5.7在windows下面的主从复制配置

    目标:自动同步Master 服务器上面的Demo数据库到Slave 服务器的Demo数据库中. 对于一些操作系统比较强而使用频率又不高的东西,往往好久不去弄就忘记了,所以要经常记录起来,方便日后查阅. ...

  4. 记一次oracle crs无法重启事故

    今天在修改了数据库参数后,关闭数据库及crs,然后重新启动了服务器,服务器启动完成之后,发现数据库无法启动,过程如下: step1:重启数据库 $ su - grid $ srvctl stop da ...

  5. Python内置函数(12)——str

    英文文档: class str(object='') class str(object=b'', encoding='utf-8', errors='strict') Return a string  ...

  6. Python-Cpython解释器支持的进程与线程-Day9

    Cpython解释器支持的进程与线程 阅读目录 一 python并发编程之多进程 1.1 multiprocessing模块介绍 1.2 Process类的介绍 1.3 Process类的使用 1.4 ...

  7. Docker1.12.6+CentOS7.3 的安装

    安装旧版的docker-engine-1.12.6 kubeadm init --api-advertise-addresses=172.16.160.211命令的时候,提示docker版本太新了 一 ...

  8. POJ-3617 Best Cow Line---字符串贪心

    题目链接: https://vjudge.net/problem/POJ-3617 题目大意: 每次都可以从字符串的首部或者尾部提取字母,使得最后的字符串的字典序最小. 思路: 贪心做即可~每次从上和 ...

  9. 分析ajax请求抓取今日头条关键字美图

    # 目标:抓取今日头条关键字美图 # 思路: # 一.分析目标站点 # 二.构造ajax请求,用requests请求到索引页的内容,正则+BeautifulSoup得到索引url # 三.对索引url ...

  10. digest-MD5认证

    digest-MD5认证机制是基于MD5算法的LINUX安全机制认证. 会比较用户端传送的杂凑值与使用者密码的杂凑值,以认证用户端. 但由于此机制必须读取使用者密码,因此,所有想透过digest-MD ...