pku 3067 Japan

题意:一个国家分为东部和西部,分别包括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;

}

 

树状数组:

View Code
 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 }

你可能感兴趣的:(pku)