1. 程式人生 > >LUOGU P3759 [TJOI2017]不勤勞的圖書管理員(樹套樹)

LUOGU P3759 [TJOI2017]不勤勞的圖書管理員(樹套樹)

++ long long sin 區間 iostream digi 討論 str clas

傳送門

解題思路

  和以前做過的一道題有點像,就是區間逆序對之類的問題,用的是\(BIT\)套權值線段樹,交換時討論一下計算答案。。跑的不如暴力快。。

代碼

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>

using namespace std;
const int N=50005;
const int M=N*200;
const int MOD=1e9+7;
typedef long long LL;

inline int rd(){
    int x=0,f=1; char ch=getchar();
    while(!isdigit(ch)) f=ch=='-'?0:1,ch=getchar();
    while(isdigit(ch)) x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
    return f?x:-x;
}

int n,m,a[N],val[N],tot,rt[N];
LL ans;

struct Segment_Tree{
    int sum[M],num[M],ls[M],rs[M];
    void update_num(int &x,int l,int r,int pos,int k){
        if(!x) x=++tot; num[x]+=k; num[x]%=MOD;
        if(l==r) return; int mid=(l+r)>>1; 
        if(pos<=mid) update_num(ls[x],l,mid,pos,k);
        else update_num(rs[x],mid+1,r,pos,k);
    }
    void update_sum(int &x,int l,int r,int pos,int k){
        if(!x) x=++tot; (sum[x]+=k)%=MOD; 
        if(l==r) return; int mid=(l+r)>>1;
        if(pos<=mid) update_sum(ls[x],l,mid,pos,k);
        else update_sum(rs[x],mid+1,r,pos,k);
    }
    int query_sum(int x,int l,int r,int L,int R){
        if(!x) return 0; if(L<=l && r<=R) return sum[x];
        int mid=(l+r)>>1,ret=0;
        if(L<=mid) ret+=query_sum(ls[x],l,mid,L,R);
        if(mid<R) (ret+=query_sum(rs[x],mid+1,r,L,R))%=MOD;
        return ret;
    }
    int query_num(int x,int l,int r,int L,int R){
        if(!x) return 0; if(L<=l && r<=R) return num[x];
        int mid=(l+r)>>1,ret=0;
        if(L<=mid) ret+=query_num(ls[x],l,mid,L,R);
        if(mid<R) (ret+=query_num(rs[x],mid+1,r,L,R))%=MOD;
        return ret;
    }
}tree2;

struct BIT{
    inline void add(int x,int k){
        for(int i=x;i<=n;i+=i&-i) {
            tree2.update_num(rt[i],1,50000,a[x],k);
            tree2.update_sum(rt[i],1,50000,a[x],k*val[x]);
        }
    }
    inline int query_sum(int l,int r,int L,int R){
        if(l>r || L>R) return 0; int ret=0;
        for(int i=r;i;i-=i&-i) (ret+=tree2.query_sum(rt[i],1,50000,L,R))%=MOD;
        for(int i=l-1;i;i-=i&-i) (ret-=tree2.query_sum(rt[i],1,50000,L,R))%=MOD;
        return (ret+MOD)%MOD;
    }
    inline int query_num(int l,int r,int L,int R){
        if(l>r || L>R) return 0; int ret=0;
        for(int i=r;i;i-=i&-i) (ret+=tree2.query_num(rt[i],1,50000,L,R))%=MOD;
        for(int i=l-1;i;i-=i&-i) (ret-=tree2.query_num(rt[i],1,50000,L,R))%=MOD;
        return (ret+MOD)%MOD;
    }
}tree1;

int main(){
    n=rd(),m=rd(); int x,y,tmp,num,num1,num2;
    for(int i=1;i<=n;i++){
        a[i]=rd(),val[i]=rd(); tree1.add(i,1);
        ans+=tree1.query_sum(1,i,a[i]+1,50000);
        ans+=1ll*tree1.query_num(1,i,a[i]+1,50000)*val[i]%MOD;
        ans%=MOD;
    }   LL sum;
    while(m--){
        x=rd(),y=rd(); if(x>y) swap(x,y);
        if(x==y) {printf("%lld\n",ans); continue;}
        if(a[x]<a[y]) (ans+=val[x]+val[y])%=MOD;
        else (ans-=val[x]+val[y])%=MOD;
        tmp=tree1.query_sum(x+1,y-1,min(a[x],a[y]),max(a[x],a[y]));
        num=tree1.query_num(x+1,y-1,min(a[x],a[y]),max(a[x],a[y]));
        num1=tree1.query_num(x+1,y-1,1,min(a[x],a[y])-1);
        num2=tree1.query_num(x+1,y-1,max(a[x],a[y])+1,50000);
        if(a[x]<a[y]) ans+=tmp*2%MOD+1ll*num*(val[x]+val[y])%MOD,ans%=MOD;
        else ans-=tmp*2%MOD+1ll*num*(val[x]+val[y])%MOD,ans%=MOD;
        sum=1ll*(val[y]-val[x])*num1%MOD+1ll*(val[x]-val[y])*num2%MOD; sum%=MOD;
        (ans+=sum)%=MOD;
        tree1.add(x,-1); tree1.add(y,-1); swap(a[x],a[y]); swap(val[x],val[y]);
        tree1.add(x,1); tree1.add(y,1); ans=(ans+MOD)%MOD; printf("%lld\n",ans);
    }
    return 0;
}   

LUOGU P3759 [TJOI2017]不勤勞的圖書管理員(樹套樹)