对于题中所给的任意两条公路,如果要相交的话,那么(设他们的序号对分别是(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 *= (BRI *)e;
19      BRI *= (BRI *)f;
20      if(c->== 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