poj 3067 Japan
| Time Limit: 1000MS | Memory Limit: 65536K | |
| Total Submissions: 14697 | Accepted: 3945 | 
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
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;
}
 
                    
                     
                    
                 
                    
                
 
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号