[bzoj4908][BeiJing2017] 开车

Posted 大奕哥&VANE

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[bzoj4908][BeiJing2017] 开车相关的知识,希望对你有一定的参考价值。

首先拍完序一一对应肯定是最优的,但是修改怎么办?我们可以局部考虑一下怎么计算答案,把点离散化一下,然后对于汽车我们看做+1,加油站看做-1,如果某个点的前缀和是0那么肯定匹配上了,否则就不是,那么贡献是什么,就是这个点的前缀和的绝对值乘上这个点和下一个点的距离(离散化以前的),不懂的话自己画图试一下就行了。那么很明显这就是差分操作,我们每次移动一个车就相当于对于数列的查分数组一个位置-1,一个位置+1,由于我们有绝对值这个棘手的操作,那么我们考虑用分块来维护。每个块里按照每个点的前缀和排一个序,然后对于一整块+1或者-1可以用懒标记记一下,然后对于负数与正数分开处理,记一下前缀和即可,我这里写的是二分找到一个0的位置,也可以记一下每个块内0的位置,动态维护,再加上基数排序可以做到O(n sqrt(n))复杂度,我写的是O(n sqrt(n) log n),也是可以过的。—— by VANE

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=50005;
const int M=150005;
const int K=400;
int a[N],b[N],c[N],d[N];
int p[M],pn,s[M],ad[K];
ll ans;
struct data{int s;ll p;}t[M];
bool cmp(data x,data y)
{
    return x.s<y.s;
}
void build(int x)
{
    for(int i=x;i<x+K;++i) t[i].p=p[i],t[i].s=s[i];
    sort(t+x,t+x+K,cmp);
    for(int i=x+1;i<x+K;++i) t[i].p+=t[i-1].p;
}
int abs(int x){return x<0?-x:x;}
void add(int l,int r,int x)
{
    int lk=(l-1)/K,rk=(r-1)/K;
    for(int i=lk*K+1;i<=(lk+1)*K;++i) s[i]+=ad[lk];ad[lk]=0;
    for(int i=l;i<=r&&i<=(lk+1)*K;++i) ans-=abs(s[i])*p[i],ans+=abs(s[i]+=x)*p[i];
    build(lk*K+1);
    for(int i=lk+1;i<rk;++i)
    {
        ad[i]+=x;
        int L=i*K+1,R=(i+1)*K,res=0;
        if(x<0)
        {    
            while(L<=R)
            {
                int mid=L+R>>1;
                if(t[mid].s+ad[i]<0){res=mid;L=mid+1;}
                else R=mid-1;
            }
            ans-=t[(i+1)*K].p;ans+=2*t[res].p;
        }
        else
        {
            while(L<=R)
            {
                int mid=L+R>>1;
                if(t[mid].s+ad[i]<=0){res=mid;L=mid+1;}
                else R=mid-1;
            }
            ans+=t[(i+1)*K].p;ans-=2*t[res].p;
        }
    }
    if(lk==rk) return;
    for(int i=rk*K+1;i<=(rk+1)*K;++i) s[i]+=ad[rk];ad[rk]=0;
    for(int i=r;i>rk*K;--i) ans-=abs(s[i])*p[i],ans+=abs(s[i]+=x)*p[i];
    build(rk*K+1);
}
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;++i) scanf("%d",a+i),p[++pn]=a[i];
    for(int i=1;i<=n;++i) scanf("%d",b+i),p[++pn]=b[i];
    int q;scanf("%d",&q);
    for(int i=1;i<=q;++i) scanf("%d%d",c+i,d+i),p[++pn]=d[i];
    sort(p+1,p+1+pn);
    pn=unique(p+1,p+1+pn)-p-1;
    for(int i=1;i<=n;++i)
    {
        s[a[i]=lower_bound(p+1,p+1+pn,a[i])-p]++;
        s[b[i]=lower_bound(p+1,p+1+pn,b[i])-p]--;
    }
    for(int i=1;i<=q;++i) d[i]=lower_bound(p+1,p+1+pn,d[i])-p;
    for(int i=1;i<=pn;++i) ans+=abs(s[i]+=s[i-1])*(p[i]=p[i+1]-p[i]);p[pn+1]=0;
    printf("%lld\n",ans);
    for(int i=1;i<=pn;i+=K)
    build(i);
    for(int i=1;i<=q;++i)
    {
        if(a[c[i]]<d[i]) add(a[c[i]],d[i]-1,-1);
        else if(a[c[i]]>d[i]) add(d[i],a[c[i]]-1,1);
        a[c[i]]=d[i];
        printf("%lld\n",ans);
    }
}

 

以上是关于[bzoj4908][BeiJing2017] 开车的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ4864[BeiJing 2017 Wc]神秘物质 Splay

[bzoj4906][BeiJing2017]喷式水战改

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

bzoj4864: [BeiJing 2017 Wc]神秘物质

bzoj4864[BeiJing 2017 Wc]神秘物质 Splay

严格次小生成树(Bzoj1977:[Beijing2010组队]次小生成树)