POJ 3067 Japan(BIT)

Description
有两排城市,这两排之间有一些城市之间有连接的道路,给出所有道路,问有多少道路是相交的
Input
第一行为用例组数t,对于每组用例,第一行三个整数n,m,k分别表示两排城市的数量以及之间的道路数量,之后k行每行两个整数x和y表示x城市和y城市有一条道路相连
Output
对于每组用例,输出道路相交的数量
Sample Input
1
3 4 4
1 4
2 3
3 2
3 1
Sample Output
Test case 1: 5
Solution
我们先把所有的道路按照x升序,x相同时y升序的方法排列。这样从头至尾便利,对于每条道路,我们只需要知道它之前有多少道路的y大于它的y就可以了,所以我们只要知道前面有多少y小于等于它的再用下标减去就可以了。而这个求有多少小于等于的过程就用树状数组来实现。我们每看到一条边,就把它的y作为下标,把树状数组对应位进行修改。这样一来,树状数组所有下标小于等于该道路的b的数的总和就是我们要求的y小于等于该道路的道路数
Code

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define maxn 1111
struct node
{
    int x,y;
}s[maxn*maxn];
long long b[maxn];
int n,m,k;
long long getnum(int x)
{
    long long sum=0;
    while(x>0)
    {
        sum+=b[x];
        x-=x&-x;
    }
    return sum;
}
void update(int x,int v)
{
    while(x<maxn)
    {
        b[x]+=v;
        x+=x&-x;
    }
}
int cmp(node a,node b)//先按x降序排,再按y升序排 
{
    if(a.x!=b.x)
        return a.x>b.x;
    return a.y>b.y;
}
int main()
{
    int t;
    scanf("%d",&t);
    int res=1;
    while(t--)
    {
        memset(b,0,sizeof(b));
        scanf("%d%d%d",&n,&m,&k);
        for(int i=0;i<k;i++)
            scanf("%d%d",&s[i].x,&s[i].y);
        sort(s,s+k,cmp);
        long long ans=0;
        for(int i=0;i<k;i++) 
        {
            ans+=getnum(s[i].y-1);//避免端点重合的情况 
            update(s[i].y,1);
        }
        printf("Test case %d: ",res++);
        printf("%I64d\n",ans);
    }
    return 0;
}

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