poj 2299 求逆序数 树状数组入门

/*
这一题题意很简单...
就是求将其排列好后所需的最小排列顺序.....
我们可以按照冒牌排序的思想来看....
也就是说....统计每个数比它本身小且在它之后的数的个数....
感觉这里不该叫做离散化,应该叫做 "紧凑化" 才对
把 n 个数据范围很大的数据 一映射到a[(1~n)] = 1.2.3...上
然后对于每个数,把它更新,
求和就是求前面小于自己的数的个数,
用当前总数-前面小于自己的数的个数 = 前面大于自己的总数
For the input sequence
9 1 0 5 4 ,
Ultra-QuickSort produces the output
0 1 4 5 9 .
answer is 6 .
最近在学树状数组,不过刚开始也没什么头绪貌似可以尝试一下
不过感觉9999999999数字太大,网上又说叫离散化+树状数组!
于是在纸上画了画,豁然开朗!
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=500002;
int A[maxn],c[maxn],n;
struct node
{
    int x,y;
}p[maxn];
int cmp(node a,node b)
{
    if(a.x!=b.x) return a.x<b.x;
    return a.y<=b.y;
}
int lowbit(int i)
{
    return i&(-i);
}
void add(int i,int d)
{
    while(i<=maxn)
    {
        c[i]+=d;
        i+=lowbit(i);
    }
}
int sum(int i)
{
    int ret=0;
    while(i)
    {
        ret+=c[i];
        i-=lowbit(i);
    }
    return ret;
}
int main()
{
    while(scanf("%d",&n),n)
    {
        __int64 ans=0;
        memset(A,0,sizeof(A));
        memset(c,0,sizeof(c));
        int i,j;
        for(i=1;i<=n;i++) scanf("%d",&p[i].x),p[i].y=i;
        sort(p+1,p+n+1,cmp);
        for(i=1;i<=n;i++) A[p[i].y]=i;
        for(i=1;i<=n;i++)
            add(A[i],1),ans+=(i-sum(A[i]));
            printf("%I64d\n",ans);
    }
    return 0;
}

你可能感兴趣的:(poj 2299 求逆序数 树状数组入门)