[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); } }
生命中真正重要的不是你遭遇了什么,而是你记住了哪些事,又是如何铭记的。