码迷,mamicode.com
首页 > 编程语言 > 详细

二分·归并排序与树状数组之逆序对 hiho1141

时间:2015-08-12 01:15:24      阅读:134      评论:0      收藏:0      [点我收藏+]

标签:

题目链接:二分·归并排序之逆序对

题目大意:N个整数,第i个数表示等级第i低的船的火力值a[i],求A船比B船等级高,但是A船火力低于B船,相当于就是求逆序数吧

解题思路:

  1. 把序列分成元素个数尽量相等的两半
  2. 把两半元素分别排序
  3. 把两个有序表合并成一个

二分归并排序做法:

/**************************************************************
    Problem:hiho 1141
    User: youmi
    Language: C++
    Result: Accepted
    Time:148ms
    Memory:7M
****************************************************************/
//#pragma comment(linker, "/STACK:1024000000,1024000000")
//#include<bits/stdc++.h>
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <map>
#include <stack>
#include <set>
#include <sstream>
#include <cmath>
#include <queue>
#include <string>
#include <vector>
#define zeros(a) memset(a,0,sizeof(a))
#define ones(a) memset(a,-1,sizeof(a))
#define sc(a) scanf("%d",&a)
#define sc2(a,b) scanf("%d%d",&a,&b)
#define sc3(a,b,c) scanf("%d%d%d",&a,&b,&c)
#define scs(a) scanf("%s",a)
#define sclld(a) scanf("%I64d",&a)
#define pt(a) printf("%d\n",a)
#define ptlld(a) printf("%I64d\n",a)
#define rep0(i,n) for(int i=0;i<n;i++)
#define rep1(i,n) for(int i=1;i<=n;i++)
#define rep_1(i,n) for(int i=n;i>=1;i--)
#define rep_0(i,n) for(int i=n-1;i>=0;i--)
#define Max(a,b) (a)>(b)?(a):(b)
#define Min(a,b) (a)<(b)?(a):(b)
#define lson (step<<1)
#define rson (lson+1)
#define esp 1e-6
#define oo 0x3fffffff
#define TEST cout<<"*************************"<<endl

using namespace std;
typedef long long ll;

int n;
const int maxn=100000+10;
ll d[maxn];
ll p[maxn];
ll ans;
void test(int l,int r)//输出排序过程,检验正确与否
{
    printf("l->%d r->%d\n",l,r);
    for(int i=l;i<=r;i++)
        printf("%d ",d[i]);
    cout<<endl;
}
void merge_sort(int l,int r)//因为每一次排序只与l--r这段有关,所以可以把这段的排序结果放在p数组里,排完后再复制回原数组
{
    if(l<r)
    {
        int mid=(l+r)>>1;
        merge_sort(l,mid);
        merge_sort(mid+1,r);
        int x=l,y=mid+1;
        int cnt=0;
        while(x<=mid||y<=r)
        {
            if(y>r||(x<=mid&&d[x]<=d[y]))
                p[cnt++]=d[x++];
            else
            {
                p[cnt++]=d[y++];
                ans+=(x-l);//每次排序左半边的下标比右半边小,所以只需要在每次放右半边的数时看看左半边已经排好了多少,相应的就知道有多少等级高但值比下标大值小的数有多少
            }
        }
        int temp=l;
        rep0(i,cnt)
            d[temp++]=p[i];
    }
}
int main()
{
    //freopen("in.txt","r",stdin);
    while(~sc(n))
    {
        rep1(i,n)
            scanf("%lld",&d[i]);
        ans=0;
        merge_sort(1,n);
        printf("%lld\n",1ll*n*(n-1)/2-ans);
    }
    return 0;
}

树状数组也是求逆序数的好方法,每放一个数,就比他小的数有多少个,也就是等级比他大但数值比他小的数量

/**************************************************************
    Problem:hiho 1141
    User: youmi
    Language: C++
    Result: Accepted
    Time:151ms
    Memory:6M
****************************************************************/
//#pragma comment(linker, "/STACK:1024000000,1024000000")
//#include<bits/stdc++.h>
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <map>
#include <stack>
#include <set>
#include <sstream>
#include <cmath>
#include <queue>
#include <string>
#include <vector>
#define zeros(a) memset(a,0,sizeof(a))
#define ones(a) memset(a,-1,sizeof(a))
#define sc(a) scanf("%d",&a)
#define sc2(a,b) scanf("%d%d",&a,&b)
#define sc3(a,b,c) scanf("%d%d%d",&a,&b,&c)
#define scs(a) scanf("%s",a)
#define sclld(a) scanf("%I64d",&a)
#define pt(a) printf("%d\n",a)
#define ptlld(a) printf("%I64d\n",a)
#define rep0(i,n) for(int i=0;i<n;i++)
#define rep1(i,n) for(int i=1;i<=n;i++)
#define rep_1(i,n) for(int i=n;i>=1;i--)
#define rep_0(i,n) for(int i=n-1;i>=0;i--)
#define Max(a,b) (a)>(b)?(a):(b)
#define Min(a,b) (a)<(b)?(a):(b)
#define lson (step<<1)
#define rson (lson+1)
#define esp 1e-6
#define oo 0x3fffffff
#define TEST cout<<"*************************"<<endl

using namespace std;
typedef long long ll;

int n;

const int maxn=100000+10;
int b[maxn],c[maxn];
struct node
{
    int val,id;
    bool operator<(const node& a)const
    {
        return val<a.val;
    }
}a[maxn];
int lowbit(int x)
{
    return x&(-x);
}
void update(int x)
{
    while(x<=n)
    {
        c[x]+=1;
        x+=lowbit(x);
    }
}
int query(int x)
{
    int res=0;
    while(x>=1)
    {
        res+=c[x];
        x-=lowbit(x);
    }
    return res;
}
int main()
{
    //freopen("in.txt","r",stdin);
    while(~sc(n))
    {
        rep1(i,n)
        {
            sc(a[i].val);
            a[i].id=i;
        }
        sort(a+1,a+n+1);//下面为离散化过程,因为单个值太大,如果开相应大小的数组就爆栈了
        b[a[1].id]=1;
        for(int i=2;i<=n;i++)
        {
            if(a[i].val!=a[i-1].val)
                b[a[i].id]=i;
            else
                b[a[i].id]=b[a[i-1].id];
        }//以上为离散化过程
        /**<rep1(i,n)
            printf("%d ",b[i]);
        cout<<endl;  */
        zeros(c);
        ll ans=0;
        rep1(i,n)
        {
            ans+=query(b[i]);
            update(b[i]);
        }
        ll temp=1ll*n*(n-1)/2-ans;
        printf("%lld\n",temp);
    }
    return 0;
}

 

二分·归并排序与树状数组之逆序对 hiho1141

标签:

原文地址:http://www.cnblogs.com/youmi/p/4722815.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!