POJ-3067 Japan---树状数组逆序对变形

题目链接:

https://vjudge.net/problem/POJ-3067

题目大意:

日本岛东海岸与西海岸分别有N和M个城市,现在修高速公路连接东西海岸的城市,求交点个数。

解题思路:

记每条告诉公路为(x,y), 即东岸的第x个城市与西岸的第y个城市修一条路。当两条路有交点时,满足(x1-x2)*(y1-y2) < 0。所以,将每条路按x从小到达排序,若x相同,按y从小到大排序。 然后按排序后的公路用树状数组在线更新,求y的逆序数之和 即为交点个数。

比如样例

1 4
2 3
3 2
3 1

排完序后

1 4
2 3
3 1
3 2

1、加入1 4,此时比4大的元素为0,交点数目为0

2、加入2 3,此时比3大的元素数目为1,交点数目为1

3、加入3 1,此时比1大的数字有两个,交点数目为3

4、加入3 2,此时比2大的数字有2个,交点数目为5

如果先加人3 2,再加入3 1的话会导致3 1这条计算交点的时候吧3 2算进去,但实际上并没有交点,所以排序顺序在x相同的y从小到大排序

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<string>
 5 #include<map>
 6 #include<set>
 7 #include<cmath>
 8 #include<algorithm>
 9 using namespace std;
10 typedef long long ll;
11 const int maxn = 1000000 + 10;
12 int n, m, T, k, cases;
13 struct node
14 {
15     int x, y;
16     bool operator <(const node& a)const
17     {
18         return x < a.x || x == a.x && y < a.y;
19     }
20 };
21 node a[maxn];
22 int tree[10000];
23 int lowbit(int x)
24 {
25     return x & (-x);
26 }
27 ll sum(int x)
28 {
29     ll ans = 0;
30     while(x)
31     {
32         ans += tree[x];
33         x -= lowbit(x);
34     }
35     return ans;
36 }
37 void add(int x, int d)
38 {
39     while(x <= m)
40     {
41         tree[x] += d;
42         x += lowbit(x);
43     }
44 }
45 int main()
46 {
47     cin >> T;
48     while(T--)
49     {
50         cin >> n >> m >> k;
51         memset(tree, 0, sizeof(tree));
52         for(int i = 1; i <= k; i++)
53         {
54             scanf("%d%d", &a[i].x, &a[i].y);
55         }
56         sort(a + 1, a + 1 + k);
57         ll ans = 0;
58         for(ll i = 1; i <= k; i++)
59         {
60             add(a[i].y, 1);
61             ans += (i - sum(a[i].y));
62         }
63         printf("Test case %d: %lld\n", ++cases, ans);
64     }
65     return 0;
66 }

 

posted @ 2018-04-25 20:04  _努力努力再努力x  阅读(219)  评论(0编辑  收藏  举报