不勤勞的圖書管理員

不勤勞的圖書管理員

題解

很明顯的一道動態逆序對的題,我們可以通過在每次交換時維護它的兩點對交換的貢獻得出答案。

不過如果我們只用O\left ( n^{2} \right )的方法暴力去維護的話就只能得到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;
}

謝謝!!! 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章