题意:有两排城市,这两排之间有一些城市之间有连接的道路,给出所有道路,问有多少道路是相交的。
分析:求逆序数。我们先把所有的道路按照a升序,a相同时b升序的方法排列。这样从头至尾便利,对于每条道路,我们只需要知道它之前有多少道路的b大于等于它的b就可以了,所以我们只要知道前面有多少b小于它的再用下标减去就可以了。而这个求有多少小于的过程就用树状数组来实现。我们每看到一条边,就把它的b作为下标,把树状数组对应位进行修改。这样一来,树状数组所有下标小于该道路的b的数的总和就是我们要求的b小于该道路的道路数。
解题代码:View Code
1 // File Name: /media/文档/源程序/实验室/poj3067.cpp 2 // Author: sheng 3 // Created Time: 2013年03月28日 星期四 13时12分48秒 4 5 #include <iostream> 6 #include <stdio.h> 7 #include <string.h> 8 #include <algorithm> 9 using namespace std; 10 11 typedef long long LL; 12 #define Max 2005 13 int maxy, maxx, point[Max]; 14 15 struct node 16 { 17 int x; 18 int y; 19 }highway[Max*Max]; 20 21 bool cmp(const node &a, const node &b) 22 { 23 if (a.x != b.x) 24 return a.x < b.x; 25 else return a.y < b.y; 26 } 27 int lowbit(int xx) 28 { 29 return xx&(-xx); 30 } 31 32 void updata(int i) 33 { 34 while (i <= maxy) 35 { 36 point[i] += 1; 37 i += lowbit(i); 38 } 39 } 40 41 LL add(int i) 42 { 43 LL sum = 0; 44 while (i > 0) 45 { 46 sum += point[i]; 47 i -= lowbit(i); 48 } 49 return sum; 50 } 51 52 int main() 53 { 54 int t, k; 55 //freopen("t.txt", "r", stdin); 56 scanf ("%d",&t); 57 for (int i = 0; i < t; i ++) 58 { 59 memset( point, 0, sizeof (point) ); 60 scanf ("%d%d%d", &maxx, &maxy, &k); 61 for (int j = 0; j < k; j ++) 62 { 63 scanf("%d%d", &highway[j].x, &highway[j].y); 64 } 65 sort (highway, highway + k, cmp); 66 LL ans = 0; 67 for (int j = 0; j < k; j ++ ) 68 { 69 ans += j - add(highway[j].y);//此add目的是为了计算不大于当前 Y 的y值个数然后j - 这个数就是比 Y 大的,也就是线段交点的数 70 updata(highway[j].y); 71 } 72 printf("Test case %d: %lld\n", i + 1, ans); 73 } 74 }