题目链接:
http://poj.org/problem?id=3067
题目大意:
有两排的城市,一排N个城市,编号为1~N,一排M个城市,编号为1~M。这两排城市之间有K条路。
路都是直线连接,问:这些路,有多少道路是相交的,并且焦点不是城市所在的点,求出交点个数。
思路:
树状数组的思想。参考网上的图,先将所有边(u,v)按u升序排列,如果u相同,则按v升序排列。可
以看出来,路(u1,v1)和路(u2,v2)如果有交点的话,u1 > u2 并且 v1 < v2,或者 u1 < u2 并且
v1 > v2,为了不重复计算,忽略后一种情况。如果排序完之后,可以发现:结果就是右边序列的逆
序数。直接建立树状数组求逆序数即可。
例如题中例子,如上图所示。排完序为:
1 4
2 3
3 1
3 2
交点个数为:0+1+2+2 = 5个。
AC代码:
#include<iostream> #include<algorithm> #include<cstdio> #include<cstring> #define LL __int64 using namespace std; const int MAXN = 1000; int Tree[MAXN+10]; struct Node { int u,v; }Edges[MAXN*MAXN]; int cmp(Node a,Node b) { if(a.u != b.u) return a.u < b.u; else return a.v < b.v; } int Lowbit(int x) { return x & (-x); } void Update(int i,int x) { while(i <= MAXN) { Tree[i] += x; i += Lowbit(i); } } LL Query(int n) { LL sum = 0; while(n > 0) { sum += Tree[n]; n -= Lowbit(n); } return sum; } int main() { int T,N,M,K,kase = 0; scanf("%d",&T); while(T--) { memset(Tree,0,sizeof(Tree)); scanf("%d%d%d",&N,&M,&K); for(int i = 0; i < K; ++i) scanf("%d%d",&Edges[i].u,&Edges[i].v); sort(Edges,Edges+K,cmp); LL ans = 0; for(int i = 0; i < K; ++i) { ans += i-Query(Edges[i].v); Update(Edges[i].v,1); } printf("Test case %d: %I64d\n",++kase, ans); } return 0; }
时间: 2024-11-16 03:52:43