poj3067 Japan 树状数组求逆序数

来源:http://www.cnblogs.com/rainydays/archive/2011/03/04/1970513.html

 分析:求逆序数。我们先把所有的道路按照a升序,a相同时b升序的方法排列。这样从头至尾便利,对于每条道路,我们只需要知道它之前有多少道路的b大于等于它的b就可以了,所以我们只要知道前面有多少b小于它的再用下标减去就可以了。而这个求有多少小于的过程就用树状数组来实现。我们每看到一条边,就把它的b作为下标,把树状数组对应位进行修改。这样一来,树状数组所有下标小于该道路的b的数的总和就是我们要求的b小于该道路的道路数。

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;

int M[1010];
int m, n, k;

struct Link{
	int x;
	int y;
}links[1010 * 1010];

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

void add(int x, int b, int *A, int size) {
	while(x <= size) {
		A[x] += b;
		x += lowbit(x);
	}
}

long long sum(int end, int *A) {
	long long r = 0;
	while(end > 0) {
		r += A[end];
		end -= lowbit(end);
	}
	return r;
}

bool cmp1(Link l, Link r) {
	if (l.x != r.x) return l.x < r.x;
	else return l.y < r.y;
}

int main() {
	int t;
	scanf("%d", &t);
	for (int i = 1; i <= t; i++) {
		scanf("%d %d %d", &n, &m, &k);
		for (int j = 0; j < k; j++)
			scanf("%d %d", &links[j].x, &links[j].y);
		sort(links, links+k, cmp1);
		/*
		for (int j = 1; j <= k; j++)
			cout<<links[j].x<<' '<<links[j].y<<endl;
		*/
		memset(M, 0, sizeof(M));
		long long ans = 0;
		for (int j = 0; j < k; j++) {
			ans += j - sum(links[j].y, M);
			add(links[j].y, 1, M, m);
		}
		printf("Test case %d: %lld\n", i, ans);

	}
	return 0;
}

你可能感兴趣的:(poj3067 Japan 树状数组求逆序数)