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; }