对于题中所给的任意两条公路,如果要相交的话,那么(设他们的序号对分别是(a,b),(c,d))(a-c)*(b-d) < 0。这个是一定成立的。也就是说如果在一个岛
屿中它序号比和它相交的那条公路的序号大的话,那么在另外一个岛屿中,一定比和它相交的那条公路的序号小。
这样的话,我们就可以对一边进行排序(从大到小,如果相等再按另外一边从大到小),这样处理之后,就可以对另外一边进行树状数组的操作了(这里用到了
上面的那么不等式)。到这基本思路已经OK了,不过结果一定要保存为__int64 或者long long
代码如下(建议自己先想)
CODE
1/**//*
2 ID:Klion
3 PROG:POJ_3067
4 LANG:C
5 树状数组,记得用__int64
6 */
7#include <stdio.h>
8#include <stdlib.h>
9#include <string.h>
10typedef struct
11{
12 int a,b;
13}BRI;
14BRI bri[1000006];//输入数据的数组
15int tree[1000006];//树状数组
16int cmp(const void *e,const void *f)
17{//按b从大到小(若相等则按a从大到小) 排序的模板
18 BRI *c = (BRI *)e;
19 BRI *d = (BRI *)f;
20 if(c->b == d->b)
21 return d->a-c->a;
22 return d->b-c->b;
23}
24void update(int x,int val)
25{//更新某个点的值
26 while(x <= 1000006)
27 {
28 tree[x] += val;
29 x += (x & -x);
30 }
31 return ;
32}
33int read(int x)
34{//得到tree[1]-tree[x]的和
35 int ret = 0;
36 while(x > 0)
37 {
38 ret += tree[x];
39 x -= (x & -x);
40 }
41 return ret;
42}
43int main(void)
44{
45 freopen("3067.in","r",stdin);
46 freopen("3067.out","w",stdout);
47 int t;
48 int n,m,k;
49 int i,j;
50 __int64 sum;
51 scanf("%d",&t);
52 for(i = 1;i <= t;i++)
53 {
54 scanf("%d%d%d",&n,&m,&k);
55 for(j = 0;j < k;j++)
56 scanf("%d%d",&bri[j].a,&bri[j].b);
57 qsort(bri,k,sizeof(bri[0]),cmp);//排序,按b从大到小排序,如果b相等的话,再按a从大到小排序
58 memset(tree,0,sizeof(tree));
59 sum = 0;
60 for(j = 0;j < k;j++)
61 {//树状数组的操作
62 sum += read(bri[j].a-1);//得到已经插入过的直线中比这条直线的a小的直线的条数,也就是和这条直线相交的结果 update(bri[j].a,1);//对这条直线进行插入操作
63 }
64 printf("Test case %d: %I64d\n",i,sum);
65 }
66 return 0;
67}
68