poj 3067 Japan(树状数组求逆序数)

链接:http://poj.org/problem?id=3067

题意:左边有n个城市,右边有m个城市,建k条道路,问有这k条道路中有多少个交点。

分析:将城市按x和y从小到大排序,对于每条道路,求前面有多少个y比当前的y大的,累加起来即可。即求逆序数,可以用树状数组实现。

求逆序数的思路:

可以把数一个个插入到树状数组中, 每插入一个数, 统计小于等于他的数的个数,对应的逆序为 i- sum( data[i] ),其中 i 为当前已经插入的数的个数, sum( data[i] )为比 小于等于data[i] 的数的个数,i- sum( data[i] ) 即比 data[i] 大的个数, 即逆序的个数。最后需要把所有逆序数求和,就是在插入的过程中边插入边求和。

另外这题要注意会超int,要用64位才能过。

AC代码如下:

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 const int N=1010;
 6 #define LL __int64
 7 int c[N];
 8 struct node{
 9     int x,y;
10     bool operator <(const node &a)const{
11         if(x==a.x)
12             return y<a.y;
13         return x<a.x;
14     }
15 }p[N*N];
16 int lowbit(int x)
17 {
18     return x&(-x);
19 }
20 void update(int x,int num)
21 {
22     while(x<=N)
23     {
24         c[x]+=num;
25         x+=lowbit(x);
26     }
27 }
28 LL sum(LL x)
29 {
30     LL s=0;
31     while(x>0)
32     {
33         s+=c[x];
34         x-=lowbit(x);
35     }
36     return s;
37 }
38 int main()
39 {
40     int t,i,k,j,n,m;
41     scanf("%d",&t);
42     for(j=1;j<=t;j++)
43     {
44         memset(c,0,sizeof(c));
45         scanf("%d%d%d",&n,&m,&k);
46         for(i=1;i<=k;i++)
47             scanf("%d%d",&p[i].x,&p[i].y);
48         sort(p+1,p+k+1);
49         LL ans=0;
50         for(i=1;i<=k;i++)
51         {
52             update(p[i].y,1);
53             ans+=i-sum(p[i].y);
54         }
55         printf("Test case %d: %I64d
",j,ans);
56     }
57     return 0;
58 }
View Code
原文地址:https://www.cnblogs.com/frog112111/p/3268303.html