hdu-2838-Cow Sorting(树状数组求逆序数)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2838

Problem Description

Sherlock's N (1 ≤ N ≤ 100,000) cows are lined up to be milked in the evening. Each cow has a unique "grumpiness" level in the range 1...100,000. Since grumpy cows are more likely to damage Sherlock's milking equipment, Sherlock would like to reorder the cows in line so they are lined up in increasing order of grumpiness. During this process, the places of any two cows (necessarily adjacent) can be interchanged. Since grumpy cows are harder to move, it takes Sherlock a total of X + Y units of time to exchange two cows whose grumpiness levels are X and Y.

Please help Sherlock calculate the minimal time required to reorder the cows.

 

Input

Line 1: A single integer: N
Lines 2..N + 1: Each line contains a single integer: line i + 1 describes the grumpiness of cow i.

 

Output

Line 1: A single line with the minimal time required to reorder the cows in increasing order of grumpiness.

 

Sample Input

 

3 2 3 1

 

Sample Output

 
7

Hint

Input Details Three cows are standing in line with respective grumpiness levels 2, 3, and 1. Output Details 2 3 1 : Initial order. 2 1 3 : After interchanging cows with grumpiness 3 and 1 (time=1+3=4). 1 2 3 : After interchanging cows with grumpiness 1 and 2 (time=2+1=3).

题目大意:给一个n个数的序列,他们是无序的,要将它转换成有序的一个序列,数字之间只能相邻的才能转换,每转换一次都要花费zhua转换的两个数的和。求最少的花费是多少。

求逆序数的对数,开一个结构体,一个记录有多少个数,一个记录前面所有sh数的和

#include<stdio.h>
#include<string.h>  
#include<math.h>  
  
//#include<map>   
//#include<set>
#include<deque>  
#include<queue>  
#include<stack>  
#include<bitset> 
#include<string>  
#include<iostream>  
#include<algorithm>  
using namespace std;  

#define ll long long  
#define INF 0x3f3f3f3f  
#define mod 1000000007
#define clean(a,b) memset(a,b,sizeof(a))// 水印 

struct node{
	ll sum,cnt;//范围爆int(血书) 
}tree[100100];
int n;

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

void updata(int i,int x,int cnt) 
{//将x后面的sum,cnt刷新 
	while(i<=n)
	{
		tree[i].cnt=tree[i].cnt+cnt;
		tree[i].sum=tree[i].sum+x;
		i=i+lowbit(i);
	}
}

int Query_cnt(int i)//求小于等于x的逆序数的个数 
{
	ll res=0;
	while(i>0)
	{
		res=res+tree[i].cnt;
		i=i-lowbit(i);
	}
	return res;
}

ll Query(int i)//求小于等于x的逆序数之和 
{
	ll res=0;
	while(i>0)
	{
		res=res+tree[i].sum;
		i=i-lowbit(i);
	}
	return res;
}

int main()
{
	while(scanf("%d",&n)!=EOF)
	{
		ll ans=0;
		clean(tree,0);
		for(int i=1;i<=n;++i)
		{
			int x;
			scanf("%d",&x);
			updata(x,x,1);//对于x这个数,刷新x后面的花费(sum),小于等于x的数量 
			ll t=i-Query_cnt(x);//找到比x大的数的个数 (逆序数的个数) 
			if(t)//相加求和,对于每个x,要交换t次,后面的大于他的数也要交换,所以求和 
				ans=ans+t*x+Query(n)-Query(x);
		}
		cout<<ans<<endl;//最后输出逆序数之和 
	}
}

猜你喜欢

转载自blog.csdn.net/qq_40482358/article/details/81208111