题意:一个国家分为东部和西部,分别包括n个和m个城市,在城市之间建k条路,问有多少个交点。(不存在三边交与一点的情况)
思路:很容易想到转化为求逆序数,可以用归并排序来求,也可以用树状数组。树状数组实现要比归并简单一点。。
需要注意:k<=10^6,最后的结果要用__int64 存储
归并:
# include<stdio.h> # include<string.h> # include<stdlib.h> struct node{ int from,to,next; }edge[1000005]; int head[1005],tol,num[1000005]; __int64 count; int temp[1000005]; int cmp(const void *a,const void *b) { return *(int *)a - *(int *)b; } void add(int a,int b) { edge[tol].from=a;edge[tol].to=b;edge[tol].next=head[a];head[a]=tol++; } void merge(int l,int mid,int r) { int a1,a2,k,i; a1=l; a2=mid+1; k=0; while(a1<=mid && a2<=r) { if(num[a1]<=num[a2]) { temp[++k]=num[a1]; count+=a2-mid-1; a1++; } else { temp[++k]=num[a2]; a2++; } } while(a1<=mid) { temp[++k]=num[a1]; count+=r-mid; a1++; } while(a2<=r) { temp[++k]=num[a2]; a2++; } for(i=1;i<=k;i++) num[i+l-1]=temp[i]; } void mergesort(int l,int r) { int mid=(l+r)/2; if(r>l) { mergesort(l,mid); mergesort(mid+1,r); merge(l,mid,r); } } int main() { int i,j,n,m,ncase,s[1005],k,ans,mm,a,b,t; scanf("%d",&ncase); for(t=1;t<=ncase;t++) { scanf("%d%d%d",&n,&m,&k); memset(head,-1,sizeof(head)); tol=0; for(i=0;i<k;i++) { scanf("%d%d",&a,&b); add(a,b); } ans=0; for(i=1;i<=n;i++) { mm=0; for(j=head[i];j!=-1;j=edge[j].next) s[++mm]=edge[j].to; qsort(s+1,mm,sizeof(s[1]),cmp); for(j=1;j<=mm;j++) num[++ans]=s[j]; } count=0; mergesort(1,ans); printf("Test case %d: %I64d\n",t,count); } return 0; }
树状数组:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 # include<stdio.h>
2 # include<string.h>
3 # include<stdlib.h>
4 struct node{
5 int from,to,next;
6 }edge[1000005];
7 int head[1005],tol,count[1005],m;
8 int cmp(const void *a,const void *b)
9 {
10 return *(int *)a - *(int *)b;
11 }
12 void add(int a,int b)
13 {
14 edge[tol].from=a;edge[tol].to=b;edge[tol].next=head[a];head[a]=tol++;
15 }
16 void insert(int i)
17 {
18 while(i<=m)
19 {
20 count[i]++;
21 i+=i&(-i);
22 }
23 }
24 int query(int i)
25 {
26 int sum=0;
27 while(i>=1)
28 {
29 sum+=count[i];
30 i-=i&(-i);
31 }
32 return sum;
33 }
34 int main()
35 {
36 int i,j,n,ncase,s[1005],k,ans,mm,a,b,t,num;
37 __int64 sum;
38 scanf("%d",&ncase);
39 for(t=1;t<=ncase;t++)
40 {
41 scanf("%d%d%d",&n,&m,&k);
42 memset(head,-1,sizeof(head));
43 tol=0;
44 for(i=0;i<k;i++)
45 {
46 scanf("%d%d",&a,&b);
47 add(a,b);
48 }
49 memset(count,0,sizeof(count));
50 sum=0;
51 ans=0;
52 for(i=1;i<=n;i++)
53 {
54 mm=0;
55 for(j=head[i];j!=-1;j=edge[j].next)
56 s[++mm]=edge[j].to;
57 qsort(s+1,mm,sizeof(s[1]),cmp);
58 for(j=1;j<=mm;j++)
59 {
60 num=query(s[j]);
61 sum+=ans-num;
62 insert(s[j]);
63 ans++;
64 }
65 }
66 printf("Test case %d: %I64d\n",t,sum);
67 }
68 return 0;
69 }