一、题目大意
两对岸,一边\(n\)个点,一边\(m\)个点,现在连\(k\)条线,问有几个交点。
二、题目解析
梳理一下这其实是一个问逆序对的问题,为什么是逆序对?
举例:
依题意可得上图,算出\(5\)个点,除了作图还有什么方法可以得到答案呢?我们不妨先把\(n\)的元素看成是有序的,例子就是如此(\(1\) \(2\) \(3\) \(3\))对应的是(\(4\) \(3\) \(2\) \(1\))因为有相同的数据存在,相同位的从小到大排序(\(4\) \(3\) \(1\) \(2\)),如果这个结果是(\(1\) \(2\) \(3\) \(4\))的话,是不是就没有交点了,因为没有逆序对存在。
把逆序对互换直到为零,操作步数就是\(5\),其实每添加一条线,增加的点数就是增加的逆序对数,还无法理解就按上述步骤模拟几组数据,明白要干什么。
剩下的就是非常经典的求逆序对问题了。
三、实现代码
#include <iostream>
#include <string.h>
#include <stdio.h>
#include <vector>
#include <map>
#include <queue>
#include <algorithm>
#include <math.h>
#include <cstdio>
using namespace std;
#define lowbit(x) (x & -x)
typedef long long LL;
const int N = 1010;
LL t[N];
struct Node {
int l, r;
//按起点由大到小排序,如果起点一样的话,那么按终点由大到小排序
//求逆序对的结构体
bool operator<(const Node &W) const {
if (l == W.l)
return r > W.r;
else
return l > W.l;
}
} a[N * N]; // k条边,上限是N*N条
void add(int x, int d) {
while (x <= N) t[x] += d, x += lowbit(x);
}
LL getsum(int x) {
LL sum = 0;
while (x) sum += t[x], x -= lowbit(x);
return sum;
}
int main() {
int T, cas = 1;
scanf("%d", &T);
while (T--) {
memset(t, 0, sizeof(t));
int n, m, k;
scanf("%d%d%d", &n, &m, &k); //岸的一边是n个,另一边是m个,下面的n,m没有再次用到
// k条线
for (int i = 1; i <= k; i++) scanf("%d%d", &a[i].l, &a[i].r);
//由大到小排序
sort(a + 1, a + 1 + k);
LL ans = 0;
//标准的树状数组求逆序对的过程
for (int i = 1; i <= k; i++) {
ans += getsum(a[i].r - 1);
add(a[i].r, 1);
}
//输出
printf("Test case %d: %lld\n", cas++, ans);
}
return 0;
}