您的位置:首页 > 其它

POJ3067 Japan【树状数组】【逆序数】

2015-05-13 22:22 344 查看
题目链接:

http://poj.org/problem?id=3067

题目大意:

有两排的城市,一排N个城市,编号为1~N,一排M个城市,编号为1~M。这两排城市之间有K条路。

路都是直线连接,问:这些路,有多少道路是相交的,并且焦点不是城市所在的点,求出交点个数。

思路:

树状数组的思想。参考网上的图,先将所有边(u,v)按u升序排列,如果u相同,则按v升序排列。可

以看出来,路(u1,v1)和路(u2,v2)如果有交点的话,u1 > u2 并且 v1 < v2,或者 u1 < u2 并且

v1 > v2,为了不重复计算,忽略后一种情况。如果排序完之后,可以发现:结果就是右边序列的逆

序数。直接建立树状数组求逆序数即可。



例如题中例子,如上图所示。排完序为:
1 4
2 3
3 1
3 2
交点个数为:0+1+2+2 = 5个。

AC代码:
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#define LL __int64
using namespace std;
const int MAXN = 1000;

int Tree[MAXN+10];

struct Node
{
int u,v;
}Edges[MAXN*MAXN];

int cmp(Node a,Node b)
{
if(a.u != b.u)
return a.u < b.u;
else
return a.v < b.v;
}

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

void Update(int i,int x)
{
while(i <= MAXN)
{
Tree[i] += x;
i += Lowbit(i);
}
}

LL Query(int n)
{
LL sum = 0;
while(n > 0)
{
sum += Tree
;
n -= Lowbit(n);
}
return sum;
}

int main()
{
int T,N,M,K,kase = 0;
scanf("%d",&T);
while(T--)
{
memset(Tree,0,sizeof(Tree));
scanf("%d%d%d",&N,&M,&K);
for(int i = 0; i < K; ++i)
scanf("%d%d",&Edges[i].u,&Edges[i].v);
sort(Edges,Edges+K,cmp);
LL ans = 0;
for(int i = 0; i < K; ++i)
{
ans += i-Query(Edges[i].v);
Update(Edges[i].v,1);
}
printf("Test case %d: %I64d\n",++kase, ans);
}

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: