• [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
    ",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
    ",ans);
        }
    }
  • 相关阅读:
    innodb临键锁锁定范围
    详解 MySql InnoDB 中的三种行锁(记录锁、间隙锁与临键锁)
    解决Jenkins邮件配置问题
    解决import模块后提示无此模块的问题
    【转】Linux下cp: omitting directory `XXX'问题解决
    Python之异常处理(执行python文件时传入参数)
    Python之发邮件
    Python之递归
    Python之参数类型、变量
    linux sed命令详解
  • 原文地址:https://www.cnblogs.com/nbwzyzngyl/p/8087537.html
Copyright © 2020-2023  润新知