• 逆序对,树状数组,归并排序


    求逆序对有三种方法,

    线段树求逆序对,

    树状数组求逆序对,

    分治求逆序对,


    先上手树状数组版的,

    有没有重复的数都好使,

     1 #include <cstdio>
     2 #include <iostream>
     3 #include <string>
     4 #include <bits/stdc++.h>
     5 
     6 using namespace std;
     7 typedef long long ll;
     8 typedef unsigned long long ull;
     9 
    10 #define MAXN 500001
    11 ll c[MAXN];
    12 //传说中的树状数组 
    13 ll n;
    14 struct shu{
    15     ll val;
    16     ll pos;
    17 }num[MAXN];
    18 bool cmp(shu a,shu b) {
    19     //这种是有重复数的 
    20     if (a.val!=b.val) return a.val>b.val;
    21     else return a.pos>b.pos; 
    22     /* retuen a.val>b.val;//这种没有重复 */
    23 }
    24 ll lowbit(ll x){
    25     return x&(-x);
    26 }
    27 ll qu_sum(ll x){
    28     ll s=0;
    29     while (x>0) {
    30         s+=c[x];
    31         x-=lowbit(x);
    32     }
    33     return s;
    34 }
    35 void updata(ll x){
    36     while (x<=n) {
    37         c[x]+=1;
    38         x+=lowbit(x);
    39     }
    40 }
    41 
    42 ll ans;
    43 int main () {
    44     scanf("%lld",&n);
    45     memset(c,0,sizeof(c));
    46     for (int i=1;i<=n;i++) {
    47         scanf("%lld",&num[i].val);
    48         num[i].pos=i;
    49     }
    50     sort(num+1,num+n+1,cmp);
    51     ans=0;
    52     for (int i=1;i<=n;i++) {
    53         updata(num[i].pos);
    54         ans+=qu_sum(num[i].pos-1);
    55     }
    56     printf("%lld
    ",ans);
    57     return 0;
    58 }

     有的时候,

    n 太大,

    可以用离散化来求,

    下面是离散化例子,

     1 #include <cstdio>
     2 #include <iostream>
     3 #include <string>
     4 #include <bits/stdc++.h>
     5 
     6 using namespace std;
     7 typedef long long ll;
     8 typedef unsigned long long ull;
     9 
    10 #define MAXN 100005
    11 ll c[MAXN],s[MAXN],a[MAXN],b[MAXN];
    12 ll n;
    13 int lowbit(int x) {return x&(-x);}
    14 void updata(ll i,int x) {
    15     while (i<=n) {
    16         c[i]+=x;
    17         i+=lowbit(i); 
    18     }
    19 }
    20 ll qu_sum(ll x) {
    21     ll sum=0;
    22     while(x>0) {
    23         sum+=c[x];
    24         x-=lowbit(x);
    25     }
    26     return sum;
    27 }
    28 int main () {
    29     //还是求逆序对 
    30     scanf("%lld",&n);
    31     ll ans=0;
    32     for (int i=1;i<=n;i++) {
    33         scanf("%lld",&a[i]);
    34         a[i]+=1000000000;
    35         b[i]=a[i];
    36     }
    37     sort(b+1,b+n+1);
    38     int len=unique(b+1,b+n+1)-b-1; 
    39     //STL库去重
    40     for (int i=1;i<=n;i++) {
    41         a[i]=lower_bound(b+1,b+len+1,a[i])-b;
    42         updata(a[i],1);
    43         ans+=(ll)i-qu_sum(a[i]);
    44     }
    45     printf("%lld
    ",ans);
    46     return 0;
    47 }

    树状数组还有好多扩展应用,

    比如下面这个,

    就是区间加,区间查询和,

     1 #include <cstdio>
     2 #include <iostream>
     3 #include <string>
     4 #include <bits/stdc++.h>
     5 
     6 using namespace std;
     7 typedef long long ll;
     8 typedef unsigned long long ull;
     9 #define MAXN 100010
    10 int a[MAXN],n,m;
    11 ll c[2][MAXN],sum[MAXN];
    12 ll lowbit(int x) {return x&(-x);}
    13 ll asksum(int k,int x) {
    14     ll ans=0;
    15     for (;x;x-=lowbit(x)) {
    16         ans+=c[k][x];
    17     }
    18     return ans;
    19 }
    20 void add(int k,int x,int y) {
    21     for (;x<=n;x+=lowbit(x)){
    22         c[k][x]+=y;
    23     }
    24 }
    25 int main () {
    26     scanf("%d%d",&n,&m);
    27     for (int i=1;i<=n;i++) {
    28         scanf("%d",&a[i]);
    29         sum[i]=sum[i-1]+a[i];
    30     }
    31     for (int i=1,l,r,d;i<=m;i++){
    32         char op[2];
    33         cin>>op;
    34         scanf("%d%d",&l,&r);
    35         if (op[0]=='C') {
    36             scanf("%d",&d);
    37             //区间加 
    38             add(0,l,d);
    39             add(0,r+1,-d);
    40             add(1,l,l*d);
    41             add(1,r+1,-(r+1)*d);
    42         }
    43         else {
    44             //区间求和
    45             ll ans=0;
    46             ans=sum[r]+(r+1)*asksum(0,r)-asksum(1,r);
    47             ans-=sum[l-1]+l*asksum(0,l-1)-asksum(1,l-1);
    48             printf("%lld
    ",ans);
    49         }
    50     } 
    51 
    52     return 0;
    53 }

    这回就很全了,


    最后还有归并排序求逆序对,

     1 #include <cstdio>
     2 #include <iostream>
     3 #include <string>
     4 #include <bits/stdc++.h>
     5 
     6 using namespace std;
     7 typedef long long ll;
     8 typedef unsigned long long ull;
     9 #define MAXN 100001
    10 ll ans,n;
    11 int s[MAXN],v[MAXN];
    12 //s[i]存数据,v[i]更改添加 
    13 
    14 void fenzhi(int x,int y) {
    15     if(x==y) {
    16         return;
    17     }
    18     int mid=(x+y)/2;
    19     fenzhi(x,mid);
    20     fenzhi(mid+1,y);
    21     int p=x,j=x,k=mid+1;
    22     while(j<=mid&&k<=y) {
    23         if(s[j]>s[k]) {
    24             ans+=mid-j+1;
    25             v[p++]=s[k++];
    26         } else v[p++]=s[j++];
    27     }
    28     while(j<=mid) {
    29         v[p++]=s[j++];
    30     }
    31     while(k<=y) {
    32         v[p++]=s[k++];
    33     }
    34     for(int i=x; i<=y; i++) {
    35         s[i]=v[i];
    36     }
    37 }
    38 int main() {
    39     cin>>n;
    40     for(int i=1; i<=n; i++) {
    41         cin>>s[i];
    42     }
    43     fenzhi(1,n);
    44     printf("%lld
    ",ans);
    45     return 0;
    46 }

    终于清了,

    逆序对还要常看看

    再来几个吧:


    单点修改,区间查询

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<cstdlib>
    using namespace std;
    int n,m;
    int c[500005];
    int lowbit(int x) {
        return (-x)&x;
    }
    void add(int pos,int x) {
        while(pos<=n) {
            c[pos]+=x;
            pos+=lowbit(pos);
        }
    }
    void input() {
        int x;
        for(int i=1; i<=n; i++) {
            scanf("%d",&x);
            add(i,x);
        }
    }
    int query(int pos) {
        int res=0;
        while(pos>0) {
            res+=c[pos];
            pos-=lowbit(pos);
        }
        return res;
    }
    int main() {
        scanf("%d%d",&n,&m);
        input();
        int f,x,y;
        for(int i=1; i<=m; i++) {
            scanf("%d%d%d",&f,&x,&y);
            if(f==1) add(x,y);
            else if(f==2) cout<<query(y)-query(x-1)<<endl;
        }
        return 0;
    }

    区间修改,单点查询:

    #include<iostream>
    #include<cstring>
    #include<queue>
    #include<cstdio>
    using namespace std;
    int c[500005];
    int n,m;
    int lowbit(int x) {
        return x&(-x);
    }
    void add(int pos,int x) {
        while(pos<=n) {
            c[pos]+=x;
            pos+=lowbit(pos);
        }
    }
    int query(int pos) {
        int res=0;
        while(pos>0) {
            res+=c[pos];
            pos-=lowbit(pos);
        }
        return res;
    }
    int main() {
        scanf("%d%d",&n,&m);
        int x=0,y;
        for(int i=1; i<=n; i++) {
            scanf("%d",&y);
            add(i,y-x);
            x=y;
        }
        int opt,k;
        for(int i=1; i<=m; i++) {
            scanf("%d",&opt);
            if(opt==1) {
                scanf("%d%d%d",&x,&y,&k);
                add(x,k);
                add(y+1,-k);
            } else if(opt==2) {
                scanf("%d",&x);
                printf("%d
    ",query(x));
            }
        }
        return 0;
    }

    以及


    区间修改,区间查询:

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    using namespace std;
    long long c[200005][2];
    int n,q;
    int lowbit(int x) {
        return x&(-x);
    }
    void add(int pos,int x,int f) {
        while(pos<=n) {
            c[pos][f]+=x;
            pos+=lowbit(pos);
        }
    }
    long long query(int pos,int f) {
        long long res=0;
        while(pos>0) {
            res+=c[pos][f];
            pos-=lowbit(pos);
        }
        return res;
    }
    long long ask(int pos) {
        long long res=(pos+1)*query(pos,0)-query(pos,1);
        return res;
    }
    int main() {
        scanf("%d",&n);
        int a=0,b,opt,x;
        for(int i=1; i<=n; i++) {
            scanf("%d",&b);
            add(i,b-a,0);
            add(i,(b-a)*i,1);
            a=b;
        }
        scanf("%d",&q);
        for(int i=1; i<=q; i++) {
            scanf("%d",&opt);
            if(opt==1) {
                scanf("%d%d%d",&a,&b,&x);
                add(a,x,0);
                add(b+1,-x,0);
                add(a,x*a,1);
                add(b+1,-x*(b+1),1);
            } else if(opt==2) {
                scanf("%d%d",&a,&b);
                printf("%lld
    ",ask(b)-ask(a-1));
            }
        }
        return 0;
    }
  • 相关阅读:
    7.21
    7.14
    7.7
    大学生失物招领平台使用体验及改进意见
    cdh集群迁移 ip更改
    klearn.preprocessing.PolynomialFeatures学习
    二元线性回归
    python学习之numpy.ewaxis
    sklearn.linear_model.LinearRegresion学习
    一元线性回归-梯度下降法-房价预测
  • 原文地址:https://www.cnblogs.com/codemaker-li/p/9796024.html
Copyright © 2020-2023  润新知