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

来源:互联网 发布:java sso单点登录 编辑:程序博客网 时间:2024/06/06 08:27

               题意:

                        左侧有一列点..从上到下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 4using 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;}