PKU 3067 Japan

PKU 3067 Japan

题目链接: http://poj.org/problem?id=3067
/**/ /*
题意:
    左边N个点,右边M个点,分别南北方向排列,1对应1,2对应2,给出
K条记录,每条记录表示左边的A点和右边的B点相连,两条相连的先会有一
个交点,现在保证任意三个线不会交与一点,问一共多少个交点。

题解:
    树状数组

思路:
    题目求的是交点的数目,仔细观察就可以发现,如果有以下四个点,A1
,B1属于左边,A2,B2属于右边,当且仅当 A1和A2的大小关系 和 B1与B2
的大小关系 相反,于是可以联想到求一个数列的逆序数的时候用到的树状数
组的成段求和。
    我们只要将读入的整数对按左边的点递增排序,如果左边点大小相同则按
右边点递增排序,每次在树状数组中统计比当前右边的点大的数的数目,然后
再将这个点插入树状数组,这就实现了一个逆序统计。
    这里需要注意的是,统计的时候需要采用__int64,因为总的交点数可能
会超过int。最大的情况是左右两边都是1000个点,并且两两有边,那么最大
的交点数量就是:
1 * (1 + 2 +  + 999)
+
2 * (1 + 2 +  + 998)
+

998 * (1 + 2)
+
999 * 1
+
1000 * 0
    可以写个程序统计一下,发现这个数字是超过int的。
    ll ans = 0;
    for(i = 1; i <= 1000; i++) {
        ans += i * (1001 - i) * (1000 - i) / 2;
    }
*/



#include 
< iostream >
#include 
< algorithm >

using   namespace  std;

struct  Double  {
    
int l, r;
}
dt[ 1000100 ];

int  N, M, K;
#define  ll __int64

int  cmp(Double a, Double b)  {
    
if(a.l == b.l)
        
return a.r < b.r;
    
return a.l < b.l;
}


int  lowbit( int  x)  {
    
return x & (-x);
}


ll c[
1010 ];
void  add( int  pos)  {
    
while(pos <= M) {
        c[pos] 
++;
        pos 
+= lowbit(pos);
    }

}


ll sum(
int  pos)  {
    ll s 
= 0;
    
while(pos > 0{
        s 
+= c[pos];
        pos 
-= lowbit(pos);
    }

    
return s;
}


int  main()  {
    
int t;
    
int i;
    
int Case = 1;




    scanf(
"%d"&t);

    
while(t--{
        memset(c, 
0sizeof(c));
        scanf(
"%d %d %d"&N, &M, &K);
        
for(i = 0; i < K; i++{
            scanf(
"%d %d"&dt[i].l, &dt[i].r);
        }

        sort(dt, dt 
+ K, cmp);

        ll ans 
= 0;
        
for(i = 0; i < K; i++{
            ans 
+= sum(M) - sum(dt[i].r);
            add(dt[i].r);
        }

        printf(
"Test case %d: %I64d\n", Case++, ans);
    }

    
return 0;
}


你可能感兴趣的:(PKU 3067 Japan)