【BZOJ4908】[BeiJing2017]开车

Description

你有n辆车,分别a1, a2, ..., an位置和n个加油站,分别在b1, b2, ... ,bn 。每个加油站只能支持一辆车的加油,所以你要把这些车开到不同的加油站加油。一个车从x位置开到y位置的代价为 |x-y| ,问如何安排车辆,使得代价之和最小。同时你有q个操作,每次操作会修改第i辆车的位置到x,你要回答每次修改操作之后最优安排方案的总代价。

Input

第一行一个正整数n,接下来一行n个整数a1, a2, ...,an,接下来一行n个整数b1, b2,... ,bn。
接下来一行一个正整数q,表示操作的个数。
接下来q行,每行有两个整数i(1 ≤ i ≤ n)和x,表示将i这辆车开到x位置的操作。
1 ≤ n, q ≤ 5 * 10^4,所有的车和加油站的范围一直在0到10^9之间。

Output

共q+1行,第一行表示一开始的最优代价。接下来q行,第i行表示操作i之后的最优代价。

Sample Input

2
1 2
3 4
1
1 3

Sample Output

4
2
【样例解释】
一开始将第一辆车开到位置4,将第二辆车开到位置3,代价为 |4-1|+|3-2|=4。
修改后第一辆车的位置变成3,代价为 |3-3|+|4-2|=2。

题解:首先不考虑修改操作,最优方案一定是:将车和加油栈按坐标排序,第i辆车去第i个加油站。那么答案如何表示?一种神奇的方法就是:将车看成+1,加油站看成-1,求前缀和s[i],ans=∑|s[i]|*(pos[i+1]-pos[i])。

那么如何维护ans和s[i]呢?考虑分块。修改小块时可以暴力维护,修改整块时,假设要将当前块内的所有s[i]++,那么我们先给整块打标记,然后ans+=(所有s[i]>=0的)(pos[i+1]-pos[i])-(所有s[i]<0的)(pos[i+1]-pos[i])。那么就在修改小块时,维护一下有多少个s[i]<=j就行了。

细节:

1.将打标记和前缀和结合起来比较麻烦,我们可以令一个块的标记=这个块之前所有元素的前缀和,然后令s[i]=当前块中的前缀和。那么一个元素的真正前缀和就是:标记+s。

2.求有多少个s[i]<=j可以用基数排序。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
const int maxn=150009;
typedef long long ll;
int n,m,nm,B;
ll ans;
int pos[maxn],s[maxn],v[maxn],q1[maxn],q2[maxn],p[500][1000],ts[500],sum[500];
ll ref[maxn],st[500][1000];
int rd()
{
int ret=0,f=1; char gc=getchar();
while(gc<'0'||gc>'9') {if(gc=='-')f=-f; gc=getchar();}
while(gc>='0'&&gc<='9') ret=ret*10+gc-'0',gc=getchar();
return ret*f;
}
struct node
{
int val,org;
}num[maxn];
bool cmp(node a,node b)
{
return a.val<b.val;
}
void tsort(int x)
{
int i;
for(i=0;i<=2*B;i++) st[x][i]=0;
for(i=x*B;i<x*B+B;i++) st[x][s[i]]+=ref[i+1]-ref[i];
for(i=1;i<=2*B;i++) st[x][i]+=st[x][i-1];
}
ll z(ll x)
{
return x>0?x:-x;
}
int main()
{
n=rd();
int i,j,a,b,c,d,e;
ll tmp;
for(i=1;i<=n;i++) num[i].org=i,num[i].val=rd();
for(i=n+1;i<=2*n;i++) num[i].org=i,num[i].val=rd();
m=rd();
for(i=n+n+1;i<=n+n+m;i++) num[i].org=i,q1[i-n-n]=rd(),num[i].val=rd();
sort(num+1,num+n+n+m+1,cmp);
num[0].val=-1<<30;
for(i=1;i<=n+n+m;i++)
{
if(num[i].val>num[i-1].val) ref[nm++]=num[i].val;
q2[num[i].org]=nm-1;
}
B=ceil(sqrt(nm));
for(i=1;i<=n;i++) v[q2[i]]++,pos[i]=q2[i];
for(i=n+1;i<=2*n;i++) v[q2[i]]--;
for(i=0;i<nm;i++)
{
if(i%B==0)
{
if(i) ts[i/B]=ts[i/B-1]+s[i-1]-B;
s[i]=B+v[i];
}
else s[i]=s[i-1]+v[i];
if(s[i]+ts[i/B]!=B)
{
tmp=z(s[i]+ts[i/B]-B)*(ref[i+1]-ref[i]);
ans+=tmp,sum[i/B]+=tmp;
}
}
ref[nm]=ref[nm-1];
for(i=0;i*B<nm;i++) tsort(i);
printf("%lld\n",ans);
for(i=1;i<=m;i++)
{
a=pos[q1[i]],b=q2[i+n+n],e=-1,v[a]--,v[b]++,pos[q1[i]]=b;
if(a>b) swap(a,b),e=1;
c=a/B,d=b/B;
ans-=sum[c],sum[c]=0;
for(j=c*B;j<c*B+B&&j<nm;j++)
{
if(j==c*B) s[j]=B+v[j];
else s[j]=s[j-1]+v[j];
if(s[j]+ts[c]!=B)
{
tmp=z(s[j]-B+ts[c])*(ref[j+1]-ref[j]);
ans+=tmp,sum[c]+=tmp;
}
}
tsort(c);
if(c==d)
{
printf("%lld\n",ans);
continue;
}
ts[d]+=e,ans-=sum[d],sum[d]=0;
for(j=d*B;j<d*B+B&&j<nm;j++)
{
if(j==d*B) s[j]=B+v[j];
else s[j]=s[j-1]+v[j];
if(s[j]+ts[d]!=B)
{
tmp=z(s[j]-B+ts[d])*(ref[j+1]-ref[j]);
ans+=tmp,sum[d]+=tmp;
}
}
tsort(d);
for(j=c+1;j<d;j++)
{
if(e==1)
{
tmp=st[j][B*2]-((B-ts[j]-1>=0)?(2*st[j][B-ts[j]-1]):0);
ans+=tmp,sum[j]+=tmp,ts[j]++;
}
else
{
tmp=-st[j][B*2]+((B-ts[j]>=0)?(2*st[j][B-ts[j]]):0);
ans+=tmp,sum[j]+=tmp,ts[j]--;
}
}
printf("%lld\n",ans);
}
return 0;
}

【BZOJ4908】[BeiJing2017]开车 分块的更多相关文章

  1. [bzoj4908][BeiJing2017]开车

    来自FallDream的博客,未经允许,请勿转载,谢谢. 你有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. [BJOI2017]开车

    [BJOI2017]开车 直接做要用栈 修改?难以直接维护 统计边的贡献! len*abs(pre)pre表示前缀car-stop 修改时候,整个区间的pre+1或者-1 分块,块内对pre排序并打标 ...

  4. 【BZOJ4861】[Beijing2017]魔法咒语 矩阵乘法+AC自动机+DP

    [BZOJ4861][Beijing2017]魔法咒语 题意:别看BZ的题面了,去看LOJ的题面吧~ 题解:显然,数据范围明显的分成了两部分:一个是L很小,每个基本词汇长度未知:一个是L很大,每个基本 ...

  5. PHP搭建大文件切割分块上传功能

    背景 在网站开发中,文件上传是很常见的一个功能.相信很多人都会遇到这种情况,想传一个文件上去,然后网页提示"该文件过大".因为一般情况下,我们都需要对上传的文件大小做限制,防止出现 ...

  6. POJ2104 K-th Number [分块做法]

    传送:主席树做法http://www.cnblogs.com/candy99/p/6160704.html 做那倒带修改的主席树时就发现分块可以做,然后就试了试 思想和教主的魔法差不多,只不过那个是求 ...

  7. HDU 4467 分块

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4467 题意:给定n个点m条边的无向图,点被染色(黑0/白1),边带边权.然后q个询问.询问分为两种: ...

  8. 2016 ACM/ICPC Asia Regional Dalian Online 1010 Weak Pair dfs序+分块

    Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)Total Submissio ...

  9. CC countari & 分块+FFT

    题意: 求一个序列中顺序的长度为3的等差数列. SOL: 对于这种计数问题都是用个数的卷积来进行统计.然而对于这个题有顺序的限制,不好直接统计,于是竟然可以分块?惊为天人... 考虑分块以后的序列: ...

随机推荐

  1. AC日记——第K大的数 51nod 1105

    1105 第K大的数 基准时间限制:1 秒 空间限制:131072 KB 分值: 40 难度:4级算法题  收藏  关注 数组A和数组B,里面都有n个整数.数组C共有n^2个整数,分别是A[0] * ...

  2. 洛谷——P2781 传教

    P2781 传教 题目背景 写完暑假作业后,bx2k去找pear玩.pear表示他要去汉中传教,于是bx2k准备跟着去围观. 题目描述 pear把即将接受传教的人排成一行,每个人从左到右的编号为1-n ...

  3. 洛谷1373小a和uim之大逃离

    题目背景 小a和uim来到雨林中探险.突然一阵北风吹来,一片乌云从北部天边急涌过来,还伴着一道道闪电,一阵阵雷声.刹那间,狂风大作,乌云布满了天空,紧接着豆大的雨点从天空中打落下来,只见前方出现了一个 ...

  4. VisualStudio 2013 Prieview体验

    今天看到VisualStudio 2013的预览版发布了,便立即下载试用了一下. 主体界面和VS2012非常类似,不过色彩要稍微丰富点. 现在支持用MS账户登录了,登陆后可以同步设置,这个小功能还是比 ...

  5. 在delphi中,如何把十进制数转换为十六进制整形数。若用inttohex只能转化为十六进制字符串。

    var b: Byte; s: string;begin s := '31'; //16进制字符串 b := StrToInt('$' + s);end; 不过要注意一点,如果在程序调试时想看b的值, ...

  6. android的多次点击事件的实现(有源码)

    三次点击事件的原理图:数组的复制(android源码的调用): 下面就是第一步: 创建long数组,里面的数字代表点击的次数. 下面是主要代码实现: system.arraycopy();里面的参数描 ...

  7. weblogic控制台登录很慢

      分类: Oracle 原文地址:weblogic控制台登录很慢 作者:paomananshan 实际是JVM在Linux下的bug 他想调用一个随机函数 但取不到 暂时的解决办法是 1)较好的解决 ...

  8. Fresco的使用及注意事项

    Fresco的使用及注意事项 时间 2016-10-17 18:32:12 DevWiki's Blog 原文  http://blog.devwiki.net/index.php/2016/10/1 ...

  9. 12.【nuxt起步】-接口请求重构

    用store把api数据交互部分重构出来,让前端更轻一点 新建 /store/gettter.js /store/actions.js /server/config/index.js Index.js ...

  10. 七天学会ASP.NET MVC (五)——Layout页面使用和用户角色管理 【转】

    http://www.cnblogs.com/powertoolsteam/p/MVC_five.html 系列文章 七天学会ASP.NET MVC (一)——深入理解ASP.NET MVC 七天学会 ...