POJ3067 Japan

题目大意

日本岛的东海岸和西海岸分别有N和M个城市,在这些城市中有K条高速公路,每条公路连接着东海岸一个城市和西海岸的一个城市,问总共这些公路有多少交叉点

题解

认真观察可以发现,只有这种情况两个线段(规范的)才是有交点的,假设两条的坐标的左右端点分别为(x1,y1)和(x2,y2),只有当x1<x2并且y1>y2或者x1>x2并且y1<y2的时候两个线段才是相交的。这样的话就很好解决这个题目了,我们只需K条高速公路的西海岸城市按编号降序排序,如果编号相同,则让东海岸的城市按编号降序排序(不能升序排序,这样的话在西海岸城市编号相同,东海岸编号不同时的情况下,在计算编号较大者它与其他公路有多少交点的时候会把编号较小的那条公路也计算进去),之后就是用树状数组处理了。

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define MAXN 1005
using namespace std;
typedef struct
{
    int x;
    int y;
}NODE;
NODE a[MAXN*MAXN];
int c[MAXN];
int n,k,m;
bool cmp(NODE a,NODE b)
{
    if(a.y==b.y) return  a.x>b.x;
    return a.y>b.y;
}
int lowbit(int x)
{
    return x&-x;
}
void add(int x)
{
    while(x<=MAXN)
    {
        c[x]++;
        x+=lowbit(x);
    }
}
int sum(int x)
{
    long long  ret=0;
    while(x>0)
    {
        ret+=c[x];
        x-=lowbit(x);
    }
    return ret;
}
int main(void)
{
    int i,T,p=0;
    long long ans;
    scanf("%d",&T);
    while(T--)
    {
        printf("Test case %d: ",++p );
        scanf("%d%d%d",&n,&m,&k);
        for(i=1;i<=k;i++)
        scanf("%d%d",&a[i].x,&a[i].y);
        memset(c,0,sizeof(c));
        sort(a+1,a+k+1,cmp);
        ans=0;
        for(i=1;i<=k;i++)
         {
             ans+=sum(a[i].x-1);
             add(a[i].x);
         }
         printf("%lld\n",ans);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/zjbztianya/p/3031642.html