poj 3067 树状数组

    这题的关键是方法。怎么才是相交的呢?一种方法是线段a的左边比线段b的左边小,同时a的右边比b的右边大。这时就可以构成一个相交。于是,我们可以根据左边的值来做降序排列,然后根据线段树来统计crosses。

排名还在上升中。加油!

#include <iostream>
#include <cstdio>
#include <fstream>
#include <algorithm>
#include <memory.h>

#define MAXN 1005
using namespace std;

int M,N,K;

int C[MAXN];
struct Node{
int n,m;
}nn[MAXN*MAXN];

bool cmp(Node a,Node b){
if(a.m==b.m) return a.n>b.n; //避免同端点的也算进去。
else return a.m>b.m;
}
inline int lowbit(int i){
return i&(-i);
}

void add(int i){
for(;i<MAXN ;C[i]+=1,i+=lowbit(i));
}

long long sum(int i){
long long s=0;
for(;i>0 ;s+=C[i],i-=lowbit(i));
return s;
}

int main()
{
int Case;
long long nSum;
int i,j,x;
//freopen("acm.in","r",stdin);
scanf("%d",&Case);
for(i=0 ;i<Case ;i++){
nSum=0;
memset(C, 0, sizeof(C));
scanf("%d%d%d",&N,&M,&K);
for(j=0 ;j<K ;j++)
scanf("%d%d",&nn[j].n,&nn[j].m);
sort(nn,nn+K,cmp);
for(x=0 ;x<K ;x++){
nSum+=sum(nn[x].n-1); //这里加的是右边比它大而左边比它小的那些线与它的焦点
//减一是为了避免左边的端点相同而多加一次。
add(nn[x].n); //这两个执行的顺序时关键
}
printf("Test case %d: %lld\n",i+1,nSum);
}
return 0;
}



你可能感兴趣的:(树状数组)