题目要求再一共 n*(n-1)/2条连线中找出所有斜率小于零的
其实就是累加每个点右下方有多少个点 或者累加每个点左上方有多少个点 这样就转换成了求逆序对的问题
注意处理一下 斜率为零或不存在的情况就好
这里抛开题目 只谈求一个排列的逆序对
在线性代数中 我们有三种方法求一个排列的逆序对
1 从左到右 看每一个元素左边有多少比它大的
2 从右到左 看每一个元素右边有多少比它小的
3 从小到大 看每个数的左边有多少比它大的 右边有多少比它小的 然后划去这个数 即划去法
我们采用第一种方法
对于一个排列 我们用a[n]数组保存 再用b[n]数组保存升序排序后的a[n] 然后基于b[n]建立线段树(值初始化为0)
遍历a[n] 对于每一个元素a[i] 先找到其在b[n]中的位置 p (如下代码所示建映射表 用map比较慢) 查询 [p n] 区间内已经有多少个数是之前已经遍历过的 累加这个值 然后更新p位置已来过即可
这样做的意义就是 看a[1]到a[i-1]中有多少个元素比a[i]要大
#include <bits/stdc++.h>
using namespace std;
#define ll long long
struct node1
{
int x;
int y;
int id;
};
struct node2
{
int l;
int r;
ll val;
};
node1 point[50010];
node2 tree[200010];
ll num[50010];
int pos[50010];
int n;
int cmp1(node1 n1,node1 n2);
int cmp2(node1 n1,node1 n2);
void build(int l,int r,int cur);
ll query(int pl,int pr,int cur);
void update(int tar,int cur);
void pushup(int cur);
int main()
{
ll sum;
int i,j,cnt;
num[0]=0;
for(i=1;i<=50000;i++)
{
num[i]=num[i-1]+i;
}
while(scanf("%d",&n)!=EOF)
{
for(i=1;i<=n;i++)
{
scanf("%d%d",&point[i].x,&point[i].y);
}
point[0].x=-1,point[0].y=-1;
sum=0,cnt=0;
sort(point+1,point+n+1,cmp1);
for(i=1;i<=n;i++)
{
if(point[i].x==point[i-1].x)
{
cnt++;
}
else
{
sum-=num[cnt];
cnt=0;
}
point[i].id=i;
}
sum-=num[cnt];
cnt=0;
sort(point+1,point+n+1,cmp2);
for(i=1;i<=n;i++)
{
if(point[i].y==point[i-1].y)
{
cnt++;
}
else
{
sum-=num[cnt];
cnt=0;
}
pos[point[i].id]=i;
}
sum-=num[cnt];
build(1,n,1);
for(i=1;i<=n;i++)
{
sum+=query(pos[i],n,1);
update(pos[i],1);
}
printf("%lld\n",sum);
}
return 0;
}
int cmp1(node1 n1,node1 n2)
{
if(n1.x==n2.x)
{
return n1.y>n2.y;
}
else
{
return n1.x<n2.x;
}
}
int cmp2(node1 n1,node1 n2)
{
if(n1.y==n2.y)
{
return n1.x>n2.x;
}
else
{
return n1.y<n2.y;
}
}
void build(int l,int r,int cur)
{
int m;
tree[cur].l=l;
tree[cur].r=r;
tree[cur].val=0;
if(l==r) return;
m=(l+r)/2;
build(l,m,cur*2);
build(m+1,r,cur*2+1);
return;
}
ll query(int pl,int pr,int cur)
{
ll ans;
if(pl<=tree[cur].l&&tree[cur].r<=pr)
{
return tree[cur].val;
}
if(tree[cur].l==tree[cur].r)
{
return 0;
}
ans=0;
if(pl<=tree[cur*2].r) ans+=query(pl,pr,cur*2);
if(pr>=tree[cur*2+1].l) ans+=query(pl,pr,cur*2+1);
return ans;
}
void update(int tar,int cur)
{
if(tree[cur].l==tree[cur].r)
{
tree[cur].val=1;
return;
}
if(tar<=tree[cur*2].r) update(tar,cur*2);
else update(tar,cur*2+1);
pushup(cur);
return;
}
void pushup(int cur)
{
tree[cur].val=tree[cur*2].val+tree[cur*2+1].val;
return;
}