poj2299 树状数组入门题

来源:互联网 发布:qq群霸屏软件 编辑:程序博客网 时间:2024/05/22 16:47
/*
  这里关键就是如何用通过一系列求和操作求出逆序对数
  假设我们对于任何一个序列 a1,a2,a3,a4,a5....an
  那么 我们首先对于每一个数 依次进行一次 update(ai,1)  (i=1....n)
  这里实质上就是 在树状数组中把大于等于ai的 数以此更新加1
  然后getsum(ai) 这其实求的就是在树状数组中1...ai ,
  1.如果在前面的过程中没有比ai小的数,那么此时用i-getsun(ai) 求出的
  就是到目前为止有多少前面有多少比他大的数 ,
  2.如果在前面有比ai小的数,因为update(ai,1)已经包括进去,然后用i-getsum(ai)就是对的,
 
  这里要用位的思维方式来理解  时间复杂度也是nlogn
  更详细的见这里
  http://blog.csdn.net/jiejiuzhang1579/article/details/6877725
*/
#include<iostream>
#include<algorithm>
#include<iterator>
#define maxn 500006
using namespace std;
int tree[maxn];
struct node
{
 int val;
 int no;
};
node num[maxn];
bool cmp(node a,node b)
{
     return a.val<b.val;
}
int lowbit(int x)
{
    return x&(-x);
}
void update(int node,int val)
{
    while(node<maxn)
    {
      tree[node]+=val;
      node+=lowbit(node);
    }
}
int getsum(int node)
{
    int sum=0;
    while(node>0)
    {
      sum+=tree[node];
      node-=lowbit(node);
    }
    return sum;
}
int main()
{
    int n;
    long long sum;
    int aa[maxn];
    while(cin>>n&&n!=0)
    {
      for(int i=1;i<=n;i++)
       {
         cin>>num[i].val;
         num[i].no=i;
       }
      sort(num+1,num+n+1,cmp);
      memset(tree,0,sizeof(tree));
      for(int i=1;i<=n;i++)
       {
         aa[num[i].no]=i;
       }
      sum=0;
      for(int i=1;i<=n;i++)
      {
        update(aa[i],1);
        sum+=(i-getsum(aa[i]));
      }
      cout<<sum<<endl;
    }
    system("pause");
    return 0;
}
原创粉丝点击