#include #include #include #include using namespace std; typedef long long LL; const int N = 1e6 + 10; int n, m; struct Node { int l, r; const bool operator<(const Node &t) const { if (l == t.l) return r < t.r; return l < t.l; } } q[N]; // 树状数组模板 typedef long long LL; #define lowbit(x) (x & -x) int c[N]; void add(int x, int d) { for (int i = x; i < N; i += lowbit(i)) c[i] += d; } LL sum(int x) { LL res = 0; for (int i = x; i; i -= lowbit(i)) res += c[i]; return res; } int main() { #ifndef ONLINE_JUDGE freopen("POJ3067.in", "r", stdin); #endif int T; scanf("%d", &T); int cnt = 0; while (T--) { memset(c, 0, sizeof c); int k; scanf("%d %d %d", &n, &m, &k); // 左右两边分别有n和m个城市,然后k行给出连边,问共有多少交叉点 for (int i = 1; i <= k; i++) scanf("%d %d", &q[i].l, &q[i].r); sort(q + 1, q + 1 + k); // 按左端点由小到大,右端点由小到大排序 // 没有离散化 // Q:为什么这里不使用离散化呢?为什么前一题 一维逆序对的数量就要使用离散化呢? // 答:因为前一题的数值1e9,而个数是1e5,所以需要映射到1~1e5的空间上,再用二分快速找出相对位置 // 而本题,数值l,r 与 个数其实是一个概念,都是小于等于1000的,无需离散化。 LL res = 0; for (int i = 1; i <= k; i++) { // 捋着原数组来,也就是一条边一条边来,逐个进入树状数组 // 当i号边进入树状数组时,在它前面进入的,肯定是左端点比自己小的,也就是值比自己小, // 那么,就检查出现的位置,也就是对应的出现在自己右侧的端点个数 res += sum(m) - sum(q[i].r); // 注意这里的sum(m),因为考查的是右端点,而右端点的上限是m add(q[i].r, 1); } printf("Test case %d: %lld\n", ++cnt, res); } return 0; }