斜率小于0的连线数量 51NOD

来源:互联网 发布:棋牌室软件 编辑:程序博客网 时间:2024/06/05 18:47

点击打开链接

题目要求再一共 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 longstruct 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;}