|
题目链接:http://poj.org/problem?id=3067
/**//* 题意: 左边N个点,右边M个点,分别南北方向排列,1对应1,2对应2,给出 K条记录,每条记录表示左边的A点和右边的B点相连,两条相连的先会有一 个交点,现在保证任意三个线不会交与一点,问一共多少个交点。
题解: 树状数组
思路: 题目求的是交点的数目,仔细观察就可以发现,如果有以下四个点,A1 ,B1属于左边,A2,B2属于右边,当且仅当 A1和A2的大小关系 和 B1与B2 的大小关系 相反,于是可以联想到求一个数列的逆序数的时候用到的树状数 组的成段求和。 我们只要将读入的整数对按左边的点递增排序,如果左边点大小相同则按 右边点递增排序,每次在树状数组中统计比当前右边的点大的数的数目,然后 再将这个点插入树状数组,这就实现了一个逆序统计。 这里需要注意的是,统计的时候需要采用__int64,因为总的交点数可能 会超过int。最大的情况是左右两边都是1000个点,并且两两有边,那么最大 的交点数量就是: 1 * (1 + 2 + + 999) + 2 * (1 + 2 + + 998) +
998 * (1 + 2) + 999 * 1 + 1000 * 0 可以写个程序统计一下,发现这个数字是超过int的。 ll ans = 0; for(i = 1; i <= 1000; i++) { ans += i * (1001 - i) * (1000 - i) / 2; } */
#include <iostream> #include <algorithm>
using namespace std;
struct Double { int l, r; }dt[1000100];
int N, M, K; #define ll __int64
int cmp(Double a, Double b) { if(a.l == b.l) return a.r < b.r; return a.l < b.l; }
int lowbit(int x) { return x & (-x); }
ll c[1010]; void add(int pos) { while(pos <= M) { c[pos] ++; pos += lowbit(pos); } }
ll sum(int pos) { ll s = 0; while(pos > 0) { s += c[pos]; pos -= lowbit(pos); } return s; }
int main() { int t; int i; int Case = 1;
scanf("%d", &t);
while(t--) { memset(c, 0, sizeof(c)); scanf("%d %d %d", &N, &M, &K); for(i = 0; i < K; i++) { scanf("%d %d", &dt[i].l, &dt[i].r); } sort(dt, dt + K, cmp);
ll ans = 0; for(i = 0; i < K; i++) { ans += sum(M) - sum(dt[i].r); add(dt[i].r); } printf("Test case %d: %I64d\n", Case++, ans); } return 0; }
|