POJ 3067 Japan(树状数组,逆序数变形)

题意:

水平方向有2n个城市点,他们分别按顺序分布在平行的两条直线上,编号都是从1n。然后现在在上直线与下直线的两个城市点之间建公路,一共建k条公路。问你这k条公路一共有多少个交点(保证最多只有两条公路会交于同一点)

题解:

   注意题目中两边的岛是这么分布的:

         1    2    3    4

          1    2    3    4

且一个点最多只有两条边相交,不可能出现3线共点的情况。假设14是一条边,那么第二行4前面的1,2,3,任意一个去和上面的2,3,4,任意连接一下都会和刚才那个边产生一个交点。

所以现在我们对所有的边按照在y行上的坐标从小到大排序,如果y相同,则按x从小到大排序。那么(x,y)边上有多少交点,只需要看x前面有多少比他大的就可以了。

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>

using namespace std;
const int maxn = 1000+10;

int c[maxn];

struct node
{
    int x,y;
    bool operator <(const node& a)const
    {
        if(y!=a.y)
            return y<a.y;
        return x<a.x;
    }
}ns[maxn*maxn];

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

int sum(int x)
{
    int res = 0;
    while(x>0)
    {
        res+=c[x];
        x -= lowbit(x);
    }
    return res;
}

void add(int x,int v)
{
    while(x<maxn)
    {
        c[x]+=v;
        x+=lowbit(x);
    }
}

int main()
{
    int t;cin>>t;
    for(int kase=1;kase<=t;kase++)
    {
        int n,m,k;
        scanf("%d%d%d",&n,&m,&k);
        for(int i=1;i<=k;i++)
        {
            scanf("%d%d",&ns[i].x,&ns[i].y);
        }

        sort(ns+1,ns+1+k);
        long long ans = 0;
        memset(c,0,sizeof c);
        for(int i=1;i<=k;i++)
        {
            ans += i-1-sum(ns[i].x);
            add(ns[i].x,1);
        }
        printf("Test case %d: %lld\n",kase,ans);
    }
}

猜你喜欢

转载自blog.csdn.net/sgh666666/article/details/80436690