对于题中所给的任意两条公路,如果要相交的话,那么(设他们的序号对分别是(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>
10
typedef struct
11

{
12
int a,b;
13
}BRI;
14
BRI bri[1000006];//输入数据的数组
15
int tree[1000006];//树状数组
16
int 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
}
24
void update(int x,int val)
25

{//更新某个点的值
26
while(x <= 1000006)
27
{
28
tree[x] += val;
29
x += (x & -x);
30
}
31
return ;
32
}
33
int 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
}
43
int 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