数据结构学习——动态逆序对

来源:互联网 发布:沅有芷兮澧有兰 知乎 编辑:程序博客网 时间:2024/06/07 19:27

解法一: 分块套BIT

利用树状数组算最初的逆序对个数 nlogn
利用树状数组算出块中比x小的数的个数 logn
遍历x所在的那个块 n/S
总复杂度O(m(lognn/S+S)+nlogn)
S取nlogn时 O(mnlogn+nlogn)

#include<cstdio>#include<cmath>#include<algorithm>using namespace std;#define M 100005#define N 80int A[M],C[M],Cnt[N];int n,m,S,G;struct BIT{    int Sum[M];    void update(int x,int a){        while(x<=n)Sum[x]+=a,x+=x&(-x);    }    int query(int x){        int ans=0;        while(x)ans+=Sum[x],x-=x&(-x);        return ans;    }}Bit[N];long long Query(int x){    long long cnt=0;    int now=(C[x]-1)/S+1;    for(int i=1;i<now;i++)cnt+=Cnt[i]-Bit[i].query(x);     for(int i=now+1;i<=G;i++)cnt+=Bit[i].query(x);    for(int i=(now-1)*S+1;i<=min(n,now*S);i++){        if(A[i]==0)continue;        if((A[i]>x&&i<C[x])||(A[i]<x&&i>C[x]))cnt++;    }    return cnt;}void Update(int x){    A[C[x]]=0;    int now=(C[x]-1)/S+1;    Cnt[now]--;    Bit[now].update(x,-1);}int main(){    long long ans=0;    scanf("%d%d",&n,&m);    S=sqrt(n*log2(n));    G=(n-1)/S+1;    for(int i=1;i<=n;i++){        scanf("%d",&A[i]),C[A[i]]=i;        ans+=i-Bit[0].query(A[i])-1;        Bit[0].update(A[i],1);    }    for(int i=1;i<=G;i++)        for(int j=i*S-S+1;j<=min(i*S,n);j++)            Bit[i].update(A[j],1),Cnt[i]++;    for(int i=1;i<=m;i++){        int x;        scanf("%d",&x);        printf("%lld\n",ans);        Update(x);        ans-=Query(x);    }    return 0;}

解法二:BIT套BIT

类似于分块
第一层的BIT就是代替分块的功能
但使用BIT的复杂度会比分块小很多 理解也难了很多
第一层的BIT对应的是下标,第二层的BIT是第一层所管辖到的子树
第二层负责维护信息,第一层负责映射出要查询的东西
可以说要更新一个值,先去找第一层
然后第一层再找第二层
可以说更新的永远是第二层
第一层只负责反馈和指挥第二层

代码实现:

#include<cstdio>#include<algorithm>#include<vector>using namespace std;#define M 100005#define pb push_back#define ll long longint A[M],W[M];int n,m;struct NODE{    int Sum[M];    void insert(int x){        while(x<=n){            Sum[x]++;            x+=x&-x;        }    }    ll query(int x){        ll ans=0;        while(x){            ans+=Sum[x];            x-=x&-x;        }        return ans;    }    ll solve(){        ll ans=0;        for(int i=1;i<=n;i++){            ans+=i-query(A[i])-1;            insert(A[i]);        }        return ans;    }}KG;struct node{    vector<int>val;    vector<int>num;    int sz;    void init(){        sort(val.begin(),val.end());        sz=val.size()-1;        //erase(unique(val.begin(),vel.end()),val.end());        for(int i=1;i<=sz;i++){            num.pb(i&-i);        }    }    void update(int x){        int k=lower_bound(val.begin(),val.end(),x)-val.begin();//从该点开始更新         while(k<(int)val.size()){            num[k]--;            k+=k&-k;        }        sz--;    }    ll query(int x){        ll ans=0;        int k=lower_bound(val.begin(),val.end(),x)-val.begin()-1;//从该点前一点查询         while(k){            ans+=num[k];            k-=k&-k;        }        return ans;    }}C[M];ll Getsize(int x){    ll sum=0;    while(x){        sum+=C[x].sz;        x-=x&-x;    }    return sum;}ll Getsum(int x,int val){    ll sum=0;    while(x){        sum+=C[x].query(val);        x-=x&-x;    }    return sum;}void Init(){    for(int i=0;i<=n;i++)C[i].val.pb(0),C[i].num.pb(0);    for(int i=1;i<=n;i++){        int x=i;        while(x<=n){            C[x].val.pb(A[i]);            x+=x&-x;        }    }}void Del(int x,int val){    while(x<=n){        C[x].update(val);        x+=x&-x;    }}int main(){    scanf("%d%d",&n,&m);    for(int i=1;i<=n;i++){        scanf("%d",&A[i]);        W[A[i]]=i;    }    Init();    for(int i=1;i<=n;i++)C[i].init();    long long tmp=KG.solve();    for(int i=1;i<=m;i++){        int x;        scanf("%d",&x);        printf("%lld\n",tmp);        ll sum1=Getsum(W[x]-1,x);        ll sum2=Getsize(W[x]-1);        ll sum3=Getsum(n,x);        tmp-=(sum2-sum1*2+sum3);        Del(W[x],x);    }    return 0;} 
原创粉丝点击