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;
    }
    线段树
  • 相关阅读:
    pku3225 区间
    pku2136 Vertical Histogram
    NOI2006 最大获利
    APIO2010 特别行动队
    停电两夜
    偷偷乐一把
    那些花儿...
    一件一块钱的小事
    web service 的Section=ResponseStatusLine 错误和skype
    杂谈
  • 原文地址:https://www.cnblogs.com/lovewhy/p/8463526.html
Copyright © 2011-2022 走看看