zoukankan      html  css  js  c++  java
  • P1908 逆序对

    题目描述

    猫猫TOM和小老鼠JERRY最近又较量上了,但是毕竟都是成年人,他们已经不喜欢再玩那种你追我赶的游戏,现在他们喜欢玩统计。最近,TOM老猫查阅到一个人类称之为“逆序对”的东西,这东西是这样定义的:对于给定的一段正整数序列,逆序对就是序列中ai>aj且i<j的有序对。知道这概念后,他们就比赛谁先算出给定的一段正整数序列中逆序对的数目。

    输入输出格式

    输入格式:

    第一行,一个数n,表示序列中有n个数。

    第二行n个数,表示给定的序列。

    输出格式:

    给定序列中逆序对的数目。

    输入输出样例

    输入样例#1: 
    6
    5 4 2 6 3 1
    
    输出样例#1: 
    11

    说明

    对于50%的数据,n≤2500

    对于100%的数据,n≤40000。

    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define date 100005
    using namespace std;
    
    int n;
    long long ans;
    int num[date];
    int sum[date];
    
    void merge_sort(int l,int r)
    {
        if(l<r)
        {
            int mid=(l+r)/2;
            int x=l;
            int y=mid+1;
            int i=l;
            merge_sort(l,mid);
            merge_sort(mid+1,r);
            while(x<=mid||y<=r)
            {
                if(y>r||(x<=mid&&num[x]<=num[y]))
                {
                    sum[i++]=num[x++];
                }
                else
                {
                    sum[i++]=num[y++];
                    ans+=mid-x+1;
                }
            }
            for(i=l;i<=r;i++)
            {
                num[i]=sum[i];
            }
        }
    }
    
    void init()
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&num[i]);
        }
        merge_sort(1,n);
        cout<<ans;
    }
    
    
    int main()
    {
        init();
        return 0;
    }
    归并排序
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    
    int n,ans,id[40005],c[40005];
    struct NUM
    {
        int num,id;
    }num[40005];
    
    bool cmp(NUM a,NUM b)
    {
        return a.num>b.num;
    }
    
    int lowbit(int x)
    {
        return x&(-x);
    }
    
    void add(int x)
    {
        while(x<=n)
        {
            c[x]++;
            x+=lowbit(x);
        }
    }
    
    int sum(int x)
    {
        int sum=0;
        while(x)
        {
            sum+=c[x];
            x-=lowbit(x);
        }
        return sum;
    }
    
    int main()
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&num[i].num);
            num[i].id=i;    //离散化处理 
        }
        sort(num+1,num+n+1,cmp);
        for(int i=1;i<=n;i++)
        {
            id[num[i].id]=i;
        }
        for(int i=1;i<=n;i++)
        {
            ans+=sum(id[i]);
            add(id[i]);
        }
        printf("%d",ans);
        return 0;
    }
    BIT 树状数组
    /*
        貌似是题解里唯一的一篇线段树题解。
        本来是要做动态逆序对的,但是我不会cdq分治,树状数组和分块不熟悉,所以想写线段树套线段树。
        然后就先来用线段树做一下不动态的。
        5倍空间消耗,比较慢,跑了近300ms 
        
        要离散化 
        指针+动态开点
    */
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    
    const int N=4e4+5;
    
    int n,a,ans;
    struct Num
    {
        int num,id;
    }num[N],aha[N];
    struct Node
    {
        Node *lson,*rson;
        int sum;
    }node[N<<2];
    
    typedef Node* Tree;
    Tree now_node,root,null;
    
    bool cmp1(Num a,Num b)
    {
        return a.num<b.num;
    }
    
    bool cmp2(Num a,Num b)
    {
        return a.id<b.id;
    }
    
    void init()
    {
        node->lson=node->rson=node;
        now_node=null=root=node;
    }
    
    int read()
    {
        char c=getchar();int num=0,f=1;
        for(;!isdigit(c);c=getchar());
        for(;isdigit(c);c=getchar())
            num=num*10+c-'0';
        return num;
    }
    
    Tree newNode()
    {
        ++now_node;
        now_node->lson=now_node->rson=null;
        return now_node;
    }
    
    int query(Tree &root,int l,int r,int L,int R)
    {
        if(root==null)
            return 0;
        if(L<=l&&r<=R)
            return root->sum;
        int mid=l+r>>1;
        int ret=0;
        if(L<=mid)
            ret+=query(root->lson,l,mid,L,R);
        if(mid<R)
            ret+=query(root->rson,mid+1,r,L,R);
        return ret;
    }
    
    void modify(Tree &root,int l,int r,int pos)
    {
        if(root==null)
            root=newNode();
        if(l==r)
        {
            root->sum=1;
            return;
        }
        int mid=l+r>>1;
        if(pos<=mid)
            modify(root->lson,l,mid,pos);
        else
            modify(root->rson,mid+1,r,pos);
        root->sum=root->lson->sum+root->rson->sum;
    }
    
    int main()
    {
        //freopen("testdata.in","r",stdin);
        init();
        n=read();
        for(int i=1;i<=n;++i)
        {
            num[i].num=read();
            num[i].id=i;
            aha[i].id=i;
        }
        sort(num+1,num+n+1,cmp1);
        for(int i=1;i<=n;++i)    //离散化,按大小编新的编号 
            aha[num[i].id].num=i;
        //sort(aha+1,aha+n+1,cmp2);    //按输入顺序排序,还原原序列 
        for(int i=1;i<=n;++i)
        {
            ans+=query(root,1,n,aha[i].num,n);    //查找在它之前的比它大的数 
            modify(root,1,n,aha[i].num);    //标记一下这个数已经出现 
        }
        printf("%d",ans);
        return 0;
    }
    线段树
  • 相关阅读:
    【BZOJ 4151 The Cave】
    【POJ 3080 Blue Jeans】
    【ZBH选讲·树变环】
    【ZBH选讲·拍照】
    【ZBH选讲·模数和】
    【CF Edu 28 C. Four Segments】
    【CF Edu 28 A. Curriculum Vitae】
    【CF Edu 28 B. Math Show】
    【CF Round 439 E. The Untended Antiquity】
    【CF Round 439 C. The Intriguing Obsession】
  • 原文地址:https://www.cnblogs.com/lovewhy/p/8463526.html
Copyright © 2011-2022 走看看