POJ 3067 - Japan 树状数组~细心估计数据范围

               题意:

                        左侧有一列点..从上到下1~N..右侧有一列点..从上到下1~M...现在告诉左右侧哪两点有边..问一共有多少个交点...

               题解:

                        可以发现一个交点出现..仅当这两个线段头尾的头尾的大小相反...比如(1,2)和(2,1)相交..因为i1比2小..后有2比1大..

                        所以把所有线段按第一个数从大到小排序.然后找逆序数就是...统计逆序数用树状数组解决..注意的是线段的总数可能到达1000*1000=10^6...


Program:

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<queue>
#include<stack>
#include<algorithm>
#include<cmath>
#include<set>
#include<map>
#include<time.h>
#define ll long long
#define oo 1000000009
#define MAXN 1000005
#define pi acos(-1.0)
#define esp 1e-30
#define MAXD 4
using namespace std;       
struct node
{
       ll x,y;
}L[MAXN<<6];
int M;
ll sum[MAXN+2];
bool cmp(node a,node b)
{
       if (a.x!=b.x) return a.x>b.x;
       return a.y>b.y;
}
void update(ll x,int k)
{
       while (k<=M)
       {
              sum[k]+=x;
              k+=k&(-k);
       }
}
ll query(int k)
{
       ll ans=0;
       while (k)
       {
              ans+=sum[k];
              k-=k&(-k);
       }
       return ans;
}  
int main()
{
       int T,N,K,cases,i;
       ll ans; 
       scanf("%d",&T);
       for (cases=1;cases<=T;cases++)
       {
              scanf("%d%d%d",&N,&M,&K);   
              for (i=1;i<=K;i++) scanf("%I64d%I64d",&L[i].x,&L[i].y);
              sort(L+1,L+1+K,cmp);
              memset(sum,0,sizeof(sum)),ans=0;
              for (i=1;i<=K;i++)   
                  ans+=query(L[i].y-1),update(1,L[i].y);   
              printf("Test case %d: %I64d\n",cases,ans); 
       }
       return 0;
}


你可能感兴趣的:(POJ 3067 - Japan 树状数组~细心估计数据范围)