• 【BZOJ4908】[BeiJing2017]开车 分块


    【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
    ",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
    ",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
    ",ans);
    	}
    	return 0;
    }
  • 相关阅读:
    docker 安装redis监控redis-stat
    maven 项目依赖打包 提示 package com.。。。。。 does not exist
    docker 建立跨主机网络
    docker-compose 安装mongodb集群==多台服务器
    docker 安装mongodb集群==多台服务器
    博客将近一年半没有更新了
    elasticsearch 使用同义词
    《SpringBoot第一篇:HelloWorld启蒙》
    go学习路线资料
    docker和k8s的概念-IaaS、PaaS、SaaS 的区别
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/7150270.html
Copyright © 2020-2023  润新知