高质量好题:[BJOI2017]开车

质量高,题目好,空白小,写不下

比较巧妙的一点是把点对之间的贡献拆成了边的贡献,这样就等价于对每一条线段维护其左边的\(|A-B|\)

这个东西的维护方法有很多,但是似乎都离不开分块。

可以用序列分块套值域分块实现 \(O(n \sqrt{n})\) 的复杂度,但是本人比较蠢,写了个用 vector 实现的 \(O(n\sqrt{n} \log{\sqrt{n}})\) 的版本。

代码写屎了最好的方式不是继续调试,而是重构。

还有,记得多封装,虽然常数大了,但是正确性会高很多,卡常是在代码正确了之后再考虑的事情。

Code
#include<bits/stdc++.h>
using namespace std;
#define il inline
#define ri register int
#define ll long long
#define ui unsigned int
il ll read(){
    bool f=true;ll x=0;
    register char ch=getchar();
    while(ch<'0'||ch>'9') {if(ch=='-') f=false;ch=getchar();}
    while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
    if(f) return x;
    return ~(--x);
}
il void write(const ll &x){if(x>9) write(x/10);putchar(x%10+'0');}
il void print(const ll &x) {x<0?putchar('-'),write(~(x-1)):write(x);putchar('\n');}
il ll max(const ll &a,const ll &b){return a>b?a:b;}
il ll min(const ll &a,const ll &b){return a<b?a:b;}
/*
把贡献拆到每条线上
每一段的贡献就是abs(左边的a-b)
那么这个东西可以用值域分块来搞
*/
const int MAXN=3e5+7;
const int MAXM=1e5+7;
#define zero 5e4
int n,a[MAXN],b[MAXN],d[MAXN];
#define pii pair<int,ll>

#define len(x) (x.second-x.first+1)
#define B 256
struct Block
{
    int tag;
    ll sum;
    vector<pii> vc;
    ll query(int l,int r){
        if(l>r) return 0;
        return vc[r].second-vc[l-1].second;
    }
    void add(){
        int pos=lower_bound(vc.begin(),vc.end(),(pii){tag,0})-vc.begin();
        sum+=query(pos,vc.size()-1);
        sum-=query(1,pos-1);
        tag--;
    }
    void del(){
        int pos=--upper_bound(vc.begin(),vc.end(),(pii){tag+1,-1})-vc.begin();
        sum+=query(1,pos);
        sum-=query(pos+1,vc.size()-1);
        tag++;
    }
}blo[MAXN/B+10];
set<pii> s;
vector<pii> vec;
pii q[MAXM];
int m,tot;
void rebuild(int id){
    int l=max(id*B,1),r=min(id*B+B-1,tot);
    if(blo[id].vc.empty()) blo[id].vc.resize(r-l+1+1);
    for(ri i=l;i<=r;++i) d[i]+=zero-blo[id].tag;
    blo[id].tag=zero;blo[id].sum=0;
    blo[id].vc[0]=(pii){-1,0};
    for(ri i=l;i<=r;++i) blo[id].vc[i-l+1]=(pii){d[i]+zero,len(vec[i])},blo[id].sum+=len(vec[i])*abs(d[i]);
    sort(blo[id].vc.begin(),blo[id].vc.end());
    for(ri i=1;i<blo[id].vc.size();++i) blo[id].vc[i].second+=blo[id].vc[i-1].second;
}
void add(int l,int r){
    if(l>r) return;
    if(l/B==r/B){
        for(ri i=l;i<=r;++i) d[i]++;
        rebuild(l/B);
        return;
    }
    add(l,l/B*B+B-1);
    add(r/B*B,r);
    for(ri i=l/B+1;i<r/B;++i) blo[i].add();
}
void del(int l,int r){
    if(l>r) return;
    if(l/B==r/B){
        for(ri i=l;i<=r;++i) d[i]--;
        rebuild(l/B);
        return;
    }
    del(l,l/B*B+B-1);
    del(r/B*B,r);
    for(ri i=l/B+1;i<r/B;++i) blo[i].del();
}
ll query(){
    ll ans=0;
    for(ri i=0;i<=tot/B;++i) ans+=blo[i].sum;
    return ans;
}
void insert(int pos){
    auto it=--s.upper_bound((pii){pos,2e9});
    if(it->first==pos&&it->second==pos) return;
    if(it->first<pos) s.insert((pii){it->first,pos-1});
    if(it->second>pos) s.insert((pii){pos+1,it->second});
    s.insert((pii){pos,pos});
    s.erase(it);
}
int main(){
    // freopen("rand.in","r",stdin);
    // freopen("2.out","w",stdout);
    n=read();
    s.insert((pii){0,1e9});
    for(ri i=1;i<=n;++i) a[i]=read(),insert(a[i]);
    for(ri i=1;i<=n;++i) b[i]=read(),insert(b[i]);
    m=read();
    for(ri i=1;i<=m;++i){
        q[i].first=read(),q[i].second=read();
        insert(q[i].second);
    } 
    vec.push_back((pii){-1,-1});
    for(auto u:s) vec.push_back(u);
    sort(vec.begin(),vec.end());
    tot=vec.size()-1;
    for(ri i=1;i<=n;++i){
        int pos=lower_bound(vec.begin(),vec.end(),(pii){a[i]+1,a[i]+1})-vec.begin();
        d[pos]++;
    }
    for(ri i=1;i<=n;++i){
        int pos=lower_bound(vec.begin(),vec.end(),(pii){b[i]+1,b[i]+1})-vec.begin();
        d[pos]--;
    }
    for(ri i=1;i<=tot;++i) d[i]+=d[i-1];
    for(ri i=0;i<=tot/B;++i) blo[i].tag=zero,rebuild(i);
    print(query());
    for(ri i=1;i<=m;++i){
        int posl=lower_bound(vec.begin(),vec.end(),(pii){a[q[i].first]+1,a[q[i].first]+1})-vec.begin();
        a[q[i].first]=q[i].second;
        int posr=lower_bound(vec.begin(),vec.end(),(pii){a[q[i].first]+1,a[q[i].first]+1})-vec.begin();
        if(posl<posr) del(posl,posr-1);
        if(posl>posr) add(posr,posl-1);
        print(query());
    }
    fprintf(stderr,"%lf",1.0*clock()/CLOCKS_PER_SEC);
    return 0;
}
posted @ 2021-07-23 12:01  krimson  阅读(54)  评论(0编辑  收藏  举报