不勤勞的圖書管理員
題解
很明顯的一道動態逆序對的題,我們可以通過在每次交換時維護它的兩點對交換的貢獻得出答案。
不過如果我們只用的方法暴力去維護的話就只能得到20分,於是我們開始想優化。
有些大佬們用分塊+CDQ分治秒了這道題,比筆者的樹套樹快了好多,不過筆者也只會打樹狀樹組套線段樹。
好了,講一下樹套樹怎麼打這道題。
我們內層用線段樹維護它的權值,外層用樹狀數組維護區間。每次查詢時減去原來區間的貢獻,交換和再加上現在的貢獻即可。
注意可以在一次查詢中維護num與sum。
源碼
//%: pragma GCC optimize(3)
//%: pragma GCC optimize(2)
//太差了,只能加這個,不然可能被卡掉。
#include<cstdio>
#include<iostream>
using namespace std;
#define ll long long
#define pii pair<int,int>
#define pll pair<ll,ll>
#define il inline
#define re register
#define gc() getchar()
template<typename _T>
void read(_T &x){
_T f=1;x=0;char s=gc();
while(s>'9'||s<'0'){if(s=='-')f=-1;s=gc();}
while(s>='0'&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=gc();}
x*=f;
}
void print(ll x) {
if(x<0) putchar('-'),x=-x;
if(!x) return ;print(x/10);putchar((x%10)^48);
}
void write(ll x) {if(!x) putchar('0');else print(x);putchar('\n');}
const int maxn=1e5+5;
const int N=1e5;
const int mo=1e9+7;
int ls[maxn*100],rs[maxn*100],sum[maxn*100],num[maxn*100];
int a[maxn],b[maxn],n,m,tot;
pii xj(pii x,pii y){
return pii{x.first+y.first,x.second+y.second};
}
pll xj1(pll x,pii y){
return pll{x.first+1ll*y.first,x.second+1ll*y.second};
}
pll xj2(pll x,pii y){
return pll{x.first-1ll*y.first,x.second-1ll*y.second};
}
#define mid (l+r>>1)
struct Segment_Tree {
void modify(int &p,int l,int r,int x,int v,int val) {
if(!p) p=++tot;sum[p]+=val;num[p]+=v;
if(l==r) return ;
if(x<=mid) modify(ls[p],l,mid,x,v,val);
else modify(rs[p],mid+1,r,x,v,val);
}
pii query(int p,int l,int r,int x,int y) {
if(!p) return pii{0,0};
if(x<=l&&r<=y) return pii{sum[p],num[p]};
pii ans=pii{0,0};
if(x<=mid) ans=xj(ans,query(ls[p],l,mid,x,y));
if(y>mid) ans=xj(ans,query(rs[p],mid+1,r,x,y));
return ans;
}
};
il ll dec(ll x,ll y) {if(x<y) x+=mo;return x-y;}
struct Binary_Indexed_Tree {
int rt[maxn];
Segment_Tree SGT[maxn];
void modify(int i,int x,int v,int val) {
for(;i<=n;i+=i&-i) SGT[i].modify(rt[i],0,N,x,v,val);
}
pll query(int l,int r,int L,int R) {
if(l>r||L>R) return pll{0,0};pll ans=pll{0,0};
while(r) ans=xj1(ans,SGT[r].query(rt[r],0,N,L,R)),r-=r&-r;l--;
while(l) ans=xj2(ans,SGT[l].query(rt[l],0,N,L,R)),l-=l&-l;
return ans;
}
}BIT;
int main() {
read(n),read(m);ll ans=0;
for(int i=1;i<=n;++i) read(a[i]),read(b[i]),BIT.modify(i,a[i],1,b[i]);
for(re int i=1;i<=n;++i){
pll tmp=BIT.query(1,i-1,a[i]+1,N);
ans=ans+tmp.first+tmp.second*b[i];
}
for(re int x,y,i=1;i<=m;++i) {
read(x),read(y);if(x>y) x^=y,y^=x,x^=y;
if(x==y){write(ans);continue;}
pll tmp;tmp=BIT.query(x+1,y-1,1,a[x]-1);
ans=dec(ans,tmp.first);
ans=dec(ans,1ll*tmp.second*b[x]);
tmp=BIT.query(x+1,y-1,a[y]+1,N);
ans=dec(ans,tmp.first);
ans=dec(ans,1ll*tmp.second*b[y]);
tmp=BIT.query(x+1,y-1,1,a[y]-1);
ans=(ans+tmp.first+1ll*tmp.second*b[y]);
tmp=BIT.query(x+1,y-1,a[x]+1,N);
ans=(ans+tmp.first+1ll*tmp.second*b[x])%mo;
if(a[x]>a[y]) ans=(ans-b[x]-b[y])%mo;
else ans=ans+b[x]+b[y];
BIT.modify(x,a[x],-1,-b[x]);BIT.modify(x,a[y],1,b[y]);
BIT.modify(y,a[y],-1,-b[y]);BIT.modify(y,a[x],1,b[x]);
a[x]^=a[y];a[y]^=a[x];a[x]^=a[y];
b[x]^=b[y];b[y]^=b[x];b[x]^=b[y];
if(ans<0) ans+=mo;if(ans>mo) ans-=mo;
write(ans);
}
return 0;
}