题目描述
猫猫TOM和小老鼠JERRY最近又较量上了,但是毕竟都是成年人,他们已经不喜欢再玩那种你追我赶的游戏,现在他们喜欢玩统计。最近,TOM老猫查阅到一个人类称之为“逆序对”的东西,这东西是这样定义的:对于给定的一段正整数序列,逆序对就是序列中ai>aj且i
输入输出格式
输入格式:
第一行,一个数n,表示序列中有n个数。
第二行n个数,表示给定的序列。
输出格式:
给定序列中逆序对的数目。
输入输出样例
说明
对于50%的数据,n≤2500
对于100%的数据,n≤40000。
#include
#include
#include
#include
#include
#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
#include
#include
#include
#include
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
#include
#include
#include
#include
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;
}
线段树