poj_3067 树状数组

题目大意

    左右两个竖排,左边竖排有N个点,从上到下依次标记为1,2,...N; 右边竖排有M个点,从上到下依次标记为1,2....M。现在从K条直线分别连接左边一个点和右边一个点,求这K条直线的交点个数(左右竖排上的点不算做交点)。 
    给出N,M,K,以及K条线的起点和终点。

题目分析

    求两两交点的问题最好固定顺序,如i和i之前的交点,这样便于统计而不重复不遗漏。在将K条线按照左边点从小到大的顺序进行排序,左边点相同按照右边点从小到大排序之后,按照顺序分析当前线和它之前的线的交点个数: 
    当前线k的左边点序号为 xa, 右边点序号为 ya, 则对于当前线k之前的那些线1--k-1,他们左边点的序号肯定小于等于xa, 这些线(1--k-1)中右边点序号大于 ya的那些线会和当前线k有一个交点。因此对于当前线k,统计之前1---k-1线的右边点在 [ya + 1--M]中的个数,形成了一个区间统计问题。 
    考虑右边点1,2....M 各对应一个统计变量 count[i], 每次分析线k,都将线k的右边点ya 对应的count[ya] ++。 这样,每次都统计 [t, M]区间内 count[i]的和。 使用树状数组来实现。

实现(c++)

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<vector>
#include<algorithm>
#include<string.h>
using namespace std;
#define MAX_CITY_NUM 1002


struct Highway{
	int east_city;
	int west_city;
	Highway(int e, int w):
	east_city(e), west_city(w){
	}
};
vector<Highway> gHws;
int gC[MAX_CITY_NUM];
int gLowbit[MAX_CITY_NUM];

bool Cmp(const Highway& h1, const Highway& h2){
	if (h1.east_city == h2.east_city)
		return h1.west_city < h2.west_city;
	return h1.east_city < h2.east_city;
}


void InitLowbit(int n){
	for (int i = 1; i <= n; i++){
		gLowbit[i] = i&(-i);
	}
}
void InitSequence(int n){
	memset(gC, 0, sizeof(gC));
}

void Update(int k, int n, int add){
	while (k <= n){
		gC[k] += add;
		k += gLowbit[k];
	}
}

int Query(int k){
	int result = 0;
	while (k > 0){
		result += gC[k];
		k -= gLowbit[k];
	}
	return result;
}

int main(){
	int cas, N, M, K, e_city, w_city;
	scanf("%d", &cas);
	InitLowbit(1001);
	for (int c = 1; c <= cas; c++){
		scanf("%d %d %d", &N, &M, &K);
		gHws.clear();
		InitSequence(M);
		for (int i = 1; i <= K; i++){
			scanf("%d %d", &e_city, &w_city);
			gHws.push_back(Highway(e_city, w_city));
		}
		sort(gHws.begin(), gHws.end(), Cmp);
		long long int crossing = 0;
		for (int i = 0; i < K; i++){
			crossing += (Query(M) - Query(gHws[i].west_city));
			Update(gHws[i].west_city, M, 1);
		}
		printf("Test case %d: %lld\n", c, crossing);
	}
	return 0;
}

 

posted @ 2015-09-09 14:51  农民伯伯-Coding  阅读(242)  评论(0编辑  收藏  举报