| ||||||||||
| Online Judge | Problem Set | Authors | Online Contests | User | ||||||
|---|---|---|---|---|---|---|---|---|---|---|
| Web Board Home Page F.A.Qs Statistical Charts | Current Contest Past Contests Scheduled Contests Award Contest | |||||||||
题意解析 + 两种解法(归并排序 + BIT)/**
一个类二分图,一边有N个城市,一边有M个城市,现在在这两类城市中连线,请你计算这些线几个交点?(每条跟其他同一条线相交只有一个交点)
M <= 1000, N <= 1000
思路:
对Ax,Ay和Bx,By两条高速公路,有相交点必须(Ax-Bx)*(Ay-By)<0,即求逆序对数量,朴素的求法是n^2 ,这里估计不行,因为边最多10W条
先按照x从小到大排序,然后再求y中的逆序对即可。因为同一个城市是不算的如:4,1和4,2不相交,不能4,2排前 4,1排后
所以x排序时只要相同的把y较小的放到前面即可,这样后面求逆序对时就不会算进去了。
(排序是为了更好算逆序数,固定住x,求y的逆序对,并不是说排了序就没有逆序对了,只是排序后无需考虑x只需看y)
求逆序对的方法有两种,一种是基本BIT求法,
另一种是归并排序的扩展应用:求逆序对
该题逆序对数量很大,需要long long
这里用的归并排序求法 or 熟悉的BIT算法
Sample Input
1
3 4 4
1 4
2 3
3 2
3 1
Sample Output
Test case 1: 5
**/
#include<cstdio>
#include<string.h>
#include<algorithm>
using namespace std;
struct Node
{
int x,y;
bool operator < (const Node& a) const
{
if(a.x == x)
return y < a.y;
else return x < a.x;
}
} node[1005 * 1005];
int a[1005 * 1005],c[1005 * 1005]; // K的范围
int N,M,K,T;
long long cnt; //
void merge_sort(int x[],int left,int right,int y[])
{
if(left < right) //大于等于不用管
{
int mid = left + (right - left) / 2;//好习惯,防溢出
//先对左右归并排序
merge_sort(x,left,mid,y);
merge_sort(x,mid+1,right,y);
//此时左右都已经排好序了,归并开销
int i = left,j = mid + 1,k = left;//左起点,右起点,临时存储起点
while(i <= mid && j <= right)
{
if(x[i] <= x[j])
{
y[k++] = x[i++];
}
else
{
y[k++] = x[j++];
cnt += mid - i + 1;//记录逆序对,相当于对右边每个值,计算左边有多少比它大的
}
}
//补上剩下的
while(i <= mid)
y[k++] = x[i++];
while(j <= right)
y[k++] = x[j++];
//临时工转正
for(i = left ; i <= right; i++)
{
x[i] = y[i];
}
}
}
void solve_by_sort() //454MS
{
for(int i = 0; i < K; ++i)
{
a[i] = node[i].y; //给归并的数组赋值
}
cnt = 0;// 重置逆序对数
merge_sort(a,0,K-1,c);
}
int BIT[1005 << 1];
void add(int n,int v){ //单点更新
while(n < 1005){
BIT[n] += v;
n += n&-n;
}
}
int sum(int n){ //区域求和
int res = 0;
while(n > 0){
res += BIT[n];
n -= n&-n;
}
return res;
}
void solve_by_BIT(){ //391MS
memset(BIT,0,sizeof(BIT));
cnt = 0;
for(int i = 0;i < K;++i){
cnt += i - sum(node[i].y); //加上j < i 的且aj > ai sum(node[i].y) 代表j < i 且 aj <= ai 的数量
add(node[i].y,1);
}
}
int main()
{
scanf("%d",&T);
for(int j = 1; j <= T; ++j)
{
scanf("%d%d%d",&N,&M,&K);
for(int i = 0; i < K; ++i)
{
scanf("%d%d",&node[i].x,&node[i].y);
}
sort(node,node+K);
//解法任选1种
//solve_by_sort();
solve_by_BIT();
printf("Test case %d: %lld\n",j,cnt);
}
return 0;
}
Followed by: Post your reply here: |
All Rights Reserved 2003-2013 Ying Fuchen,Xu Pengcheng,Xie Di
Any problem, Please Contact Administrator