• BZOJ4889 & 洛谷3759:[TJOI2017]不勤劳的图书管理员——题解


    https://www.lydsy.com/JudgeOnline/problem.php?id=4889

    https://www.luogu.org/problemnew/show/P3759

    加里敦大学有个帝国图书馆,小豆是图书馆阅览室的一个书籍管理员。他的任务是把书排成有序的,所以无序的书让他产生厌烦,两本乱序的书会让小豆产生这两本书页数的和的厌烦度。现在有n本被打乱顺序的书,在接下来m天中每天都会因为读者的阅览导致书籍顺序改变位置。因为小豆被要求在接下来的m天中至少要整理一次图书。小豆想知道,如果他前i天不去整理,第i天他的厌烦度是多少,这样他好选择厌烦度最小的那天去整理。

    最开始以为看的题解很naive,后来发现是自己太naive了。

    看起来就像是查逆序对,对于l和r的交换,其贡献的变更只与[l+1,r-1]这些区间有关,可以变成查询这段区间内有多少数满足与l和r构成逆序对。

    这个明显可以主席树做。

    然而之后你需要交换这两个数……emmm待修改主席树呗。

    其实就是树状数组套一个动态开点线段树(因为本质都差不多就都叫成主席树好了。)

    剩下的就是码码码了。

    (注意取模对常数的影响。)

    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    const int N=5e4+5;
    const int p=1e9+7;
    inline int read(){
        int X=0,w=0;char ch=0;
        while(ch<'0'||ch>'9'){w|=ch=='-';ch=getchar();}
        while(ch>='0'&&ch<='9')X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
        return w?-X:X;
    }
    struct tree{
        int l,r;
        ll v,c;
    }tr[N*200];
    int rt[N],pool,n,m;
    ll ans,a[N],v[N],b[N],cnt[N];
    inline int lowbit(int x){return x&(-x);}
    inline void add(int x,int y){
        for(int i=x;i<=n;i+=lowbit(i))b[i]+=y,cnt[i]++;
    }
    inline ll qry_val(int x){
        ll res=0;
        for(int i=x;i;i-=lowbit(i))res+=b[i];
        return res;
    }
    inline ll qry_cnt(int x){
        ll res=0;
        for(int i=x;i;i-=lowbit(i))res+=cnt[i];
        return res;
    }
    inline void insert(int &x,int l,int r,int pos,int v,int w){
        if(!x)x=++pool;
        tr[x].v+=v;tr[x].c+=w;
        if(l==r)return;
        int mid=(l+r)>>1;
        if(pos<=mid)insert(tr[x].l,l,mid,pos,v,w);
        else insert(tr[x].r,mid+1,r,pos,v,w);
    }
    inline void ins(int i,int x,int y,int w){
        for(;i<=n;i+=lowbit(i))insert(rt[i],1,n,x,y,w);
    }
    inline ll sqv(int x,int l,int r,int l1,int r1){
        if(r<l1||r1<l)return 0;
        if(l1<=l&&r<=r1)return tr[x].v;
        int mid=(l+r)>>1;
        return sqv(tr[x].l,l,mid,l1,r1)+sqv(tr[x].r,mid+1,r,l1,r1);
    }
    inline ll sqc(int x,int l,int r,int l1,int r1){
        if(r<l1||r1<l)return 0;
        if(l1<=l&&r<=r1)return tr[x].c;
        int mid=(l+r)>>1;
        return sqc(tr[x].l,l,mid,l1,r1)+sqc(tr[x].r,mid+1,r,l1,r1);
    }
    inline ll query_val(int l,int r,int l1,int r1){
        if(l>r||l1>r1)return 0;
        l--;ll res=0;
        for(int i=r;i;i-=lowbit(i))res=(res+sqv(rt[i],1,n,l1,r1))%p;
        for(int i=l;i;i-=lowbit(i))res=(res-sqv(rt[i],1,n,l1,r1))%p;
        return (res+p)%p;
    }
    inline ll query_cnt(int l,int r,int l1,int r1){
        if(l>r||l1>r1)return 0;
        l--;ll res=0;
        for(int i=r;i;i-=lowbit(i))res=(res+sqc(rt[i],1,n,l1,r1))%p;
        for(int i=l;i;i-=lowbit(i))res=(res-sqc(rt[i],1,n,l1,r1))%p;
        return (res+p)%p;
    }
    inline void check(ll &x){
        while(x>=p)x-=p;
        while(x<0)x+=p;
    }
    int main(){
        n=read(),m=read();
        for(int i=1;i<=n;i++){
            a[i]=read(),v[i]=read();
            ins(i,a[i],v[i],1);
        }
        for(int i=n;i>=1;i--){
            add(a[i],v[i]);
            ans=(ans+qry_val(a[i]-1)+qry_cnt(a[i]-1)*v[i])%p;
        }
        for(int i=1;i<=m;i++){
            int l=read(),r=read();
            if(l==r){printf("%lld
    ",ans);continue;}
            if(l>r)swap(l,r);
            ans=ans+query_val(l+1,r-1,1,a[r]-1);check(ans);
            ans=ans+query_cnt(l+1,r-1,1,a[r]-1)*v[r];check(ans);
            ans=ans-query_val(l+1,r-1,a[r]+1,n);check(ans);
            ans=ans-query_cnt(l+1,r-1,a[r]+1,n)*v[r];check(ans);
            ans=ans+query_val(l+1,r-1,a[l]+1,n);check(ans);
            ans=ans+query_cnt(l+1,r-1,a[l]+1,n)*v[l];check(ans);
            ans=ans-query_val(l+1,r-1,1,a[l]-1);check(ans);
            ans=ans-query_cnt(l+1,r-1,1,a[l]-1)*v[l];check(ans);
            if(a[l]>a[r])ans-=v[l]+v[r];
            else ans+=v[l]+v[r];
            check(ans);
            ins(l,a[l],-v[l],-1);ins(r,a[r],-v[r],-1);
            swap(a[l],a[r]);swap(v[l],v[r]);
            ins(l,a[l],v[l],1);ins(r,a[r],v[r],1);
            printf("%lld
    ",ans);
        }
        return 0;
    }

    +++++++++++++++++++++++++++++++++++++++++++

    +本文作者:luyouqi233。               +

    +欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/ +

    +++++++++++++++++++++++++++++++++++++++++++

  • 相关阅读:
    Path文件操作实例
    Cache缓存对象缓存对象
    Session对象实例
    移动端适配问题
    webpack4 优化性能
    webpack源码分析
    wepack源码解析1
    webpack面试题
    asnyc await
    node 知识
  • 原文地址:https://www.cnblogs.com/luyouqi233/p/8973654.html
Copyright © 2020-2023  润新知