poj3067(二维偏序+树状数组)

题目链接:http://poj.org/problem?id=3067

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

 题意理解:

日本计划迎接ACM-ICPC世界总决赛,场地必须修建许多道路。

日本是一个高岛,东海岸有N个城市,西海岸有M个城市(M<=500000,N<=500000)。将修建K条高速公路。每个海岸的城市编号为1,2...从北到南。

每条高速公路都是直线,连接东海岸城市和西海岸城市。建设资金由ACM提供担保。其中很大一部分是由高速公路之间的交叉口数量决定的。最多有两条高速公路在同一地点交叉。

编写一个计算高速公路之间交叉口数量的程序。              

输入              

输入文件以T开始-测试用例的数量。

每个测试用例都以三个数字开始——N,M,K。

接下来的每一条K线都包含两个数字——高速公路连接的城市数量。第一个是东海岸的城市编号,第二个是西海岸的城市编号。              

输出              

对于每个测试用例,在标准输出上写一行:              

测试用例(用例号):(交叉口数量) 

题解:经典的二维偏序问题,只不过比上一个题(poj2352)多了求逆序数的过程。

 先设东海岸的城市编号为 x ,则西海岸为 y ,不难想到,当有交叉口时,满足的条件是(x1-x2)*(y1-y2)<0。

即x1y2或者x1>x2时,y1

 所以我们就有了一个很经典的策略,我们可以把所有的高速公路按照x升序排序,若x相等则按照y升序排序。

这样我们从前往后枚举的时候就不用考虑x了,相当于求排序后y的逆序数。

为什么呢?因为排序后,前面的x值一定小于等于后面的,即保证x1y2的就行了。

之后就是很经典的树状数组的应用——求逆序数(详解请参考:poj2299),这个题可以说是两个题的综合吧。

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define PI atan(1.0)*4
#define e 2.718281828
#define rp(i,s,t) for (i = (s); i <= (t); i++)
#define RP(i,s,t) for (i = (t); i >= (s); i--)
#define ll long long
#define ull unsigned long long
#define mst(a,b) memset(a,b,sizeof(a))
#define push_back() pb()
#define fastIn                    \
    ios_base::sync_with_stdio(0); \
    cin.tie(0);
using namespace std;
inline int read()
{
    int a=0,b=1;
    char c=getchar();
    while(c<'0'||c>'9')
    {
        if(c=='-')
            b=-1;
        c=getchar();
    }
    while(c>='0'&&c<='9')
    {
        a=(a<<3)+(a<<1)+c-'0';
        c=getchar();
    }
    return a*b;
}
inline void write(int n)
{
    if(n<0)
    {
        putchar('-');
        n=-n;
    }
    if(n>=10)
        write(n/10);
    putchar(n%10+'0');
}
const int N=5e5+7;
int a[N],c[N];
//用树状数组c维护一段区间小于当前位置值的个数
//a数组用来存储排序后的结果
int n,m,k;
int lowbit(int x){
    return x&-x;
}
int query(int i){//查询i之前比i小的数的个数
    int res=0;
    while(i>0){
        res+=c[i];
        i-=lowbit(i);
    }
    return res;
}
void update(int i,int val){
    while(i<=m){//注意是m,n在这个题没有用
        c[i]+=val;
        i+=lowbit(i);
    }
}
struct node{
    int x,y;
    bool operator < (const node & others){//按照x升序排序,若x相等则按照y升序排序
        return x==others.x?y

 

你可能感兴趣的:(树状数组)