POJ 3067 Japan (树状数组 && 控制变量)
题意: 西海岸和东海岸有分别有n (1~n)个和m (1~m)个城市, 两个海岸的城市之间有k条公路连通, 公路会相交, 现在给出城市和公路的信息问你由这些公路组成的复杂交通有多少个交点 (如果两个条公路的起点或者终点相同那这两点不算做相交)
分析:先分析题目案例可以知道当y1>y2时,这样是肯定会有交点的。可以根据这个特性很快就可以发现这个就是个求逆序对的问题。但是又是不完全的正确,因为这样分析出来的答案是6,结果错误。现在在来分析是哪里出现的错误,是(3,1)与(3,2)这里的问题,分析题目可知到,如果起点或者终点相同那就不算是香蕉,所以可以得出结论,如果x相等的时候,逆序对不存在,即将y的值对调。同时我们又可以发现前面的这些性质都是在x按升序的情况下成立,所以现在问题的解决就很简单了,按x升序排,相等的话按照y升序排,然后在求得逆序对。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<stdio.h> #include<iostream> #include<algorithm> #include<string> #include<string.h> #include<set> #define LL long long #define lowbit(i) (i&(-i)) using namespace std; int c[1001], n, k, m; void add(int i, int val) { while(i<=m){ c[i] += val; i += lowbit(i); } } LL sum(int i) { LL ans = 0; while(i>0){ ans += c[i]; i -= lowbit(i); } return ans; } struct no { int x, y; }arr[10000000]; bool cmp(const no fir, const no sec) { if(fir.x == sec.x) return fir.y < sec.y; return fir.x < sec.x; } int main(void) { int nCase; scanf("%d", &nCase); for(int t=1; t<=nCase; t++){ memset(c, 0, sizeof(c)); scanf("%d%d%d", &n, &m, &k); for(int i=0; i<k; i++){ scanf("%d%d", &arr[i].x, &arr[i].y); } sort(arr, arr+k, cmp); LL ans = 0; for(int i=0; i<k; i++){ ans += i - sum(arr[i].y); add(arr[i].y, 1); } printf("Test case %d: %lld\n", t, ans); } return 0; }