您的位置:首页 > 其它

[复习]树状数组求逆序对 光荣的梦想

2017-10-12 19:04 405 查看
题目描述

Prince对他在这片大陆上维护的秩序感到满意,于是决定启程离开艾泽拉斯。在他动身之前,Prince决定赋予King_Bette最强大的能量以守护世界、保卫这里的平衡与和谐。在那个时代,平衡是个梦想。因为有很多奇异的物种拥有各种不稳定的能量,平衡瞬间即被打破。KB决定求助于你,帮助他完成这个梦想。

一串数列即表示一个世界的状态。

平衡是指这串数列以升序排列,而从一串无序数列到有序数列需要通过交换数列中的元素来实现。KB的能量只能交换相邻两个数字。他想知道他最少需要交换几次就能使数列有
4000
序。

输入格式

第一行为数列中数的个数 N(n≤100000)。

第二行为 N 个数a1~an(每个数小于100000),表示当前数列的状态。

输出格式

输出一个整数,表示最少需要交换几次能达到平衡状态。

样例数据

输入

4

2 1 4 3

输出

2

备注

本题另外一种描述:

给定一个序列a1,a2,…,an,如果存在i<j并且ai>aj,那么我们称之为逆序对,求逆序对的数目。

分析:树状数组求逆序对模板。代码比较难想,其实就是说每个数前面数的总数减去现在它前面小于它的数的个数,得到了大于它的数的个数,也就是逆序对数。

好吧,其实不难想,之前在想c[i]是干嘛用的,结果只是离散化了一下。这道题数据够小,不用c不sort直接把a往树状数组里放都可以(记得把数组开大)。

代码

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<cctype>
#include<iomanip>
#include<queue>
#include<set>
using namespace std;

int getint()
{
int sum=0,f=1;
char ch;
for(ch=getchar();!isdigit(ch)&&ch!='-';ch=getchar());
if(ch=='-')
{
f=-1;
ch=getchar();
}
for(;isdigit(ch);ch=getchar())
sum=(sum<<3)+(sum<<1)+ch-48;
return sum*f;
}

const int maxn=100010;
struct node{
int c,pos;
}a[maxn];
int n,sum[maxn],c[maxn];
long long ans;

bool comp(const node &a,const node &b)
{
if(a.c==b.c)
return a.pos<b.pos;
return a.c<b.c;
}

int lowbit(int x)
{
return x & (-x);
}

void update(int x)
{
for(;x<=n;x+=lowbit(x))
sum[x]++;
}

int query(int x)
{
int res=0;
for(;x>0;x-=lowbit(x))
res+=sum[x];

return res;
}

int main()
{
freopen("glory.in","r",stdin);
freopen("glory.out","w",stdout);

n=getint();
for(int i=1;i<=n;++i)
a[i].c=getint(),a[i].pos=i;

sort(a+1,a+n+1,comp);

for(int i=1;i<=n;++i)
c[a[i].pos]=i;

for(int i=1;i<=n;++i)
{
update(c[i]);
ans+=i-query(c[i]);
}

cout<<ans<<'\n';
return 0;
}


本题结。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: