線段樹 ZOJ 1440 Bone Sort

題目鏈接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=440

哎哎,看了別人的代碼看不懂~~所以,這是 我真正自己想的題目~~~只不過A完10分鐘還是沒有看懂別人的代碼什麼意思,並且我甚至不知道題目什麼意思~~


題目大意:(題目描述我也不知道,看別人中文翻譯做的)求多少個逆序數,並求【任意2個交換】這種交換方式 進行多少次以後可以讓它變成正序~~

算法:線段樹

思路:求逆序數這個不說了,求交換次數完全是自己瞎猜猜對的,暫時沒有證明過程,我只是把需要交換的數字先放到屬於他的地方~~~

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std ;

#define lson l, m, rt << 1
#define rson m+1, r, rt << 1 | 1
#define mid int m = (l+r) >> 1
#define LL long long

int w[456456], cnt[456456], a[456456], p[456456];

void update(int d, int k, int l, int r, int rt)
{
	if(l == r)
	{
		cnt[rt] = 1;
		return ;
	}
	mid ;
	if(d <= m)
		update(d, k, lson);
	else update(d, k, rson);
	cnt[rt] = cnt[rt << 1] + cnt[rt << 1 | 1];
}


int query(int L, int R, int l, int r, int rt)
{
	if(L <= l && r <= R)
	{
		return cnt[rt];
	}
	int ret = 0;
	mid ;
	if(L <= m)
		ret += query(L, R, lson);
	if(m < R)
		ret += query(L, R, rson);
	return ret ;
}

int bin(int key, int r)
{
	int l = 0;
	while(l <= r)
	{
		mid ;
		if(w[m] == key)
			return m;
		if(key <= w[m])
			r = m-1;
		else l = m+1;
	}
	return -1;
}
int main()
{
	int n;
	while(scanf("%d", &n) != EOF)
	{
		int i;
		for(i = 0; i < n; i ++)
		{
			scanf("%d", &a[i]);
			w[i] = a[i];
		}
		sort(w, w+n);
		LL ans = 0;
		memset(cnt, 0, sizeof(cnt));
		for(i = 0; i < n; i ++)
		{
			a[i] = bin(a[i], n-1);
			ans += query(a[i], n-1, 0, n-1, 1);
			update(a[i], 1, 0, n-1, 1);
		}

		for(i = 0; i < n; i ++)
		{
			p[i] = i;
		}
		int sum = 0;

		for(i = 0; i < n; i ++)
		{
			while(p[i] != a[i])
			{
				sum ++;
				int place = p[a[i]];
				int temp = a[i];
				a[i] = a[place];
				a[place] = temp;
			}
		}

		printf("%d\n%lld\n", sum, ans);
	}
	return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章