Description
Input
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;
}