您的位置:首页 > 其它

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

2014-07-31 22:29 429 查看
Japan

Time Limit:1000MS Memory Limit:65536KB 64bit IO Format:%I64d & %I64u
Submit
Status

Description

Japan plans to welcome the ACM ICPC World Finals and a lot of roads must be built for the venue. Japan is tall island with N cities on the East coast and M cities on the West coast (M <= 1000, N <= 1000). K superhighways will be
build. Cities on each coast are numbered 1, 2, ... from North to South. Each superhighway is straight line and connects city on the East coast with city of the West coast. The funding for the construction is guaranteed by ACM. A major portion of the sum is
determined by the number of crossings between superhighways. At most two superhighways cross at one location. Write a program that calculates the number of the crossings between superhighways.

Input

The input file starts with T - the number of test cases. Each test case starts with three numbers – N, M, K. Each of the next K lines contains two numbers – the numbers of cities connected by the superhighway. The first one is
the number of the city on the East coast and second one is the number of the city of the West coast.

Output

For each test case write one line on the standard output:

Test case (case number): (number of crossings)

Sample Input

1
3 4 4
1 4
2 3
3 2
3 1


Sample Output

Test case 1: 5


题意:一个岛的东部有N个城市分别依次编号1,2,3,。。N;西部有M个城市分别依次编号1,2,3,。。M。现要在东西部之间修建高速公路,给出每条要修铁路所连接的两城市,问所有铁路共有多少各交叉点。

心得:开始一直没想到怎么做,然后看网上大神的思路,设第一条铁路连接的两城市为x1,y1,第一条铁路连接的两城市为x2,y2,才知道满足交叉的条件是(x1-x2)*(y1-y2)<0.好聪明。。。

由此又想到了另一个思路,由于他们各个岛是依次编号排开的,则只需按照所有铁路其中西部或东部一边的坐标排序,这样再看另一部,只需求出其中的逆序数即可。

分析:说到求逆序数,据说可以用归并排序做,一直没时间搞呢,回头一定补上,不过这好不容易学回树状数组,就用这个搞了。

用树状数组来弄还挺简单的,特别方便。只需要,依次把各个值city[i]加到树状数组里,注意每次加的时候,是c[city[i]]++,这里只需加1即可,然后边加边查,加进去的时候,查询当前节点的和,i - sum(city[i])就是该节点的逆序数,这样把所有节点都加入的时候,也就把所有节点的逆序数都求出来了,加起来就是这个序列的逆序数了。详见代码

PS:一定要注意要用long long,否则是过不了的。还有就是我自己的傻了吧唧的错误——存铁路的数组开小了,一直RE,当时郁闷坏了。。。切记

AC代码:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <cmath>
#include <cstdlib>
#include <ctime>
#define LL long long
#define INF 0x7fffffff
using namespace std;
const int maxn = 1000 + 10;
LL c[maxn];      //树状数组
int n,m,k;
struct Node     //铁路
{
    LL x,y;
};
Node node[maxn*maxn];     //注意是maxn*maxn !!!

bool cmp(const Node a,const Node b)      //排序函数,对x升序排,相等时再按y升序排
{
    if(a.x == b.x)  return a.y < b.y;
    return a.x < b.x;
}

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

LL sum(LL x)                    //注意用long long
{
    LL ret = 0;
    while(x > 0)
    {
        ret += c[x];
        x -= lowbit(x);
    }
    return ret;
}

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

int main()
{
    int T;
    LL ans;
    scanf("%d",&T);
    for(int t=1; t<=T; t++)
    {
        scanf("%d%d%d",&n,&m,&k);
        ans = 0;
        memset(c,0,sizeof(c));
        for(int i=1; i<=k; i++)
            scanf("%lld%lld",&node[i].x,&node[i].y);
        sort(node+1,node+k+1,cmp);
        for(int i=1; i<=k; i++)
        {
            add(node[i].y,1);             //加入节点
            ans += i - sum(node[i].y);      //求各节点逆序数加在一起
        }
        printf("Test case %d: %lld\n",t,ans);
    }
    return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: