题意:一个国家分为东部和西部,分别包括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;
}
树状数组:
![ContractedBlock.gif](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![ExpandedBlockStart.gif](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.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 }