bzoj4889 [Tjoi2017]不勤劳的图书管理员

题目描述

题解:

很考验读题能力的一道题……

首先我们知道要求的是一个类似逆序对的东西,统计时要加上两端权值。

考虑先把初始$ans$求出来,后续操作只会改变$[l,r]$内部关系,这里分块处理。

对于$ans$有影响的有:与端点有关的逆序对形成/破坏次数,已经中间节点与两端关系。

块内用树状数组维护小于等于$x$的有几个,还有小于等于$x$的权值和是多少。

再维护一下块内总权值就行了。

代码:

#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N = 50050;
const ll  MOD = 1000000007;
template<typename T>
inline void read(T&x)
{
    T f = 1,c = 0;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){c=c*10+ch-'0';ch=getchar();}
    x = f*c;
}
int n,m,B,bel[N],lp[400],rp[400],siz[400];
ll sum[400];
template<typename T>
void Mod(T&x){if(x>=MOD)x-=MOD;}
struct BIT
{
    int c[N];
    void up(int x,ll d){while(x<N)Mod(c[x]+=d),x+=(x&-x);}
    ll down(int x){ll ret=0;while(x)Mod(ret+=c[x]),x-=(x&-x);return ret;}
};
BIT v1[400],v2[400],v0[2];
int pos[N],val[N],pla[N];
int main()
{
//    freopen("tt.in","r",stdin);
    read(n),read(m);
    B = (int)sqrt(n);
    for(int i=1;i<=n;i++)
        bel[i]=((i-1)/B)+1;
    for(int i=1;i<=bel[n];i++)
        lp[i]=(i-1)*B+1,rp[i]=min(i*B,n),siz[i] = rp[i]-lp[i]+1;
    for(int a,b,i=1;i<=n;i++)
    {
        read(a),read(b);
        v1[bel[i]].up(a,1);
        v2[bel[i]].up(a,b);
        pla[i] = a,pos[a] = i,val[a] = b,Mod(sum[bel[i]]+=b);
    }
    ll ans = 0;
    for(int i=n;i>=1;i--)
    {
        Mod(ans+=(v0[0].down(pla[i])*val[pla[i]]%MOD+v0[1].down(pla[i]))%MOD);
        v0[0].up(pla[i],1);
        v0[1].up(pla[i],val[pla[i]]);
    }
    for(int x,y,i=1;i<=m;i++)
    {
        read(x),read(y);x = pla[x],y = pla[y];
        if(x==y)
        {
            printf("%lld\n",ans%MOD);
            continue;
        }
        if(pos[x]>pos[y])swap(x,y);
        if(x>y)Mod(ans+=MOD-(val[x]+val[y]));
        else Mod(ans+=val[x]+val[y]);
        if(bel[pos[y]]-bel[pos[x]]<=1)
        {
            for(int j=pos[x]+1;j<pos[y];j++)
            {
                if(pla[j]>x)Mod(ans+=val[pla[j]]+val[x]);
                else Mod(ans+=MOD-(val[pla[j]]+val[x]));
                if(pla[j]<y)Mod(ans+=val[pla[j]]+val[y]);
                else Mod(ans+=MOD-(val[pla[j]]+val[y]));
            }
        }else
        {
            for(int j=bel[pos[x]]+1;j<bel[pos[y]];j++)
            {
                int nx = v1[j].down(x),ny = v1[j].down(y);
                Mod(ans+=MOD-(val[x]*nx%MOD+val[y]*(siz[j]-ny)%MOD)%MOD);
                Mod(ans+=(val[x]*(siz[j]-nx)%MOD+val[y]*ny%MOD)%MOD);
                nx = v2[j].down(x),ny = v2[j].down(y);
                Mod(ans+=(sum[j]-nx+ny+MOD)%MOD);
                Mod(ans+=MOD-(sum[j]+nx-ny+MOD)%MOD);
            }
            for(int j=pos[x]+1;j<=rp[bel[pos[x]]];j++)
            {
                if(pla[j]>x)Mod(ans+=val[pla[j]]+val[x]);
                else Mod(ans+=MOD-(val[pla[j]]+val[x]));
                if(pla[j]<y)Mod(ans+=val[pla[j]]+val[y]);
                else Mod(ans+=MOD-(val[pla[j]]+val[y]));
            }
            for(int j=lp[bel[pos[y]]];j<=pos[y]-1;j++)
            {
                if(pla[j]>x)Mod(ans+=val[pla[j]]+val[x]);
                else Mod(ans+=MOD-(val[pla[j]]+val[x]));
                if(pla[j]<y)Mod(ans+=val[pla[j]]+val[y]);
                else Mod(ans+=MOD-(val[pla[j]]+val[y]));
            }
        }
        Mod(sum[bel[pos[x]]]+=(val[y]-val[x]+MOD)%MOD);
        Mod(sum[bel[pos[y]]]+=(val[x]-val[y]+MOD)%MOD);
        v1[bel[pos[x]]].up(x,-1);
        v1[bel[pos[y]]].up(y,-1);
        v1[bel[pos[x]]].up(y,1);
        v1[bel[pos[y]]].up(x,1);
        v2[bel[pos[x]]].up(x,-val[x]);
        v2[bel[pos[y]]].up(y,-val[y]);
        v2[bel[pos[x]]].up(y,val[y]);
        v2[bel[pos[y]]].up(x,val[x]);
        swap(pos[x],pos[y]);
        pla[pos[x]]=x;
        pla[pos[y]]=y;
        printf("%lld\n",ans%MOD);
    }
    return 0;
}
View Code

 

posted @ 2019-04-17 22:55  LiGuanlin  阅读(321)  评论(0编辑  收藏  举报