Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 14697 | Accepted: 3945 |
Description
Input
Output
Sample Input
1 3 4 4 1 4 2 3 3 2 3 1
Sample Output
Test case 1: 5
Source
题意:顺序给两组平行的点依次编号1~N和1~M,给定K个线段在两组点之间,求相交(cross)的线段对有多少个,同一个起点或终点不算相交。
思路:树状数组,首先对x进行排序,x相等则按y进行排序,排序后以y作为树状数组。当有一条连线时,我们知道与这条连线有交点的情况有两种,(a[i].x>a[j].x&&a[i].y<a[j].y) 和 (a[i].x<a[j].x&&a[i].y>a[j].y) ,但是我们已经将数据排好序了,那么第二种情况就可以不用在当前考虑,我们只要知道a[i].y 到 m之间有多少条连线即可,与第二种情况相连的情况由a[j].y去计算。
于是计算当前这条连线有多少个交叉点即:getsum(m)-getsum(a[i].y)。
AC代码:
#include <stdio.h>
#include <string.h>
#include <algorithm>
#define maxn 2000
using namespace std;
#define ll __int64
ll c[maxn*maxn];
struct node
{
int x,y;
}nn[maxn*maxn];
int n,m,k;
bool cmp( node a,node b)
{
return a.x==b.x?a.y<b.y:a.x<b.x;
}
int lowbit( int i)
{
return i&(-i);
}
void updata( int i)
{
while(i<=m)
{
c[i]+=1;
i+=lowbit(i);
}
}
ll sum( int i)
{
ll s=0;
while(i>0)
{
s+=c[i];
i-=lowbit(i);
}
return s;
}
int main( )
{
int test;
int cases=0;
scanf("%d",&test);
while(test--)
{
memset(c,0,sizeof(c));
scanf("%d%d%d",&n,&m,&k);
for( int i=1;i<=k;i++)
{
scanf("%d%d",&nn[i].x,&nn[i].y);
}
sort(nn+1,nn+k+1,cmp);
ll ans=0;
for( int i=1;i<=k;i++)
{
ans+=sum(m)-sum(nn[i].y);
updata(nn[i].y);
}
printf("Test case %d: %I64d\n",++cases,ans);
}
return 0;
}