【51NOD 1107 斜率小于0的连线数量】 离散化+权值线段树

51NOD1107斜率小于0的连线数量
题意就是二维平面上N个点之间共有C(n,2)条连线。求这C(n,2)条线中斜率小于0的线的数量
我们将两个点的坐标描述一下就是. A(ax,ay),B(bx,by)0bx>axby<ay A 点 为 ( a x , a y ) , B 点 为 ( b x , b y ) 斜 率 小 于 0 也 就 是 b x > a x 且 b y < a y ,那么这就是一个经典的二维偏序问题,由于题目规定 ax=bx|ay=by a x = b x | a y = b y 的情况都不算,所以我们只要以第一关键字为x的顺序,第二关键字为y的逆序,进行排序,这样就能保证当x不相等时只有小于他的x会更新他,当x相等时也只有之前的大于他的y会更新他,之后离散化建一颗权值线段树,单点更新区间求和就可以了。
代码

#include<stdio.h>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn = 5e4+5;
int n,Hash[maxn];
struct data
{
    int x,y;
}p[maxn];
bool cmp(const data &a,const data &b)
{
    if(a.x==b.x) return a.y<b.y;
    return a.x<b.x;
}
struct T
{
    int l,r,mid;
    int sum;
}tree[maxn<<2];
void push_up(int rt)
{
    tree[rt].sum=tree[rt<<1].sum+tree[rt<<1|1].sum;
}
void build(int rt,int l,int r)
{
    tree[rt].l=l;
    tree[rt].r=r;
    tree[rt].sum=0;
    if(l==r)  return ;
    int mid=tree[rt].mid=l+r>>1;
    build(rt<<1,l,mid);
    build(rt<<1|1,mid+1,r);
    push_up(rt);
    return ;
}
int query(int rt,int pos)
{
    if(tree[rt].r<pos) return 0;
    if(tree[rt].l>pos) return tree[rt].sum;
    int ans=0;
    if(pos<tree[rt<<1].r) ans+=query(rt<<1,pos);
    if(pos<tree[rt<<1|1].r) ans+=query(rt<<1|1,pos);
    return ans;
}
void  update(int rt,int pos)
{
    if(tree[rt].l==tree[rt].r)
    {
        tree[rt].sum++;
        return ;
    }
    if(pos<=tree[rt].mid) update(rt<<1,pos);
    else update(rt<<1|1,pos);
    push_up(rt);
    return ;
}
int GetId(int x)
{
    return lower_bound(Hash+1,Hash+1+n,x)-Hash;
}
vector<int> v;
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d%d",&p[i].x,&p[i].y);
    for(int i=1;i<=n;i++) Hash[i]=p[i].y;
    sort(p+1,p+1+n,cmp);
    sort(Hash+1,Hash+1+n);
    int MAX = unique(Hash+1,Hash+1+n)-Hash-1;
    build(1,1,MAX);
    long long ans=0;
    for(int i=1;i<=n;i++)
    {
        int pos=GetId(p[i].y);
        ans+=query(1,pos);
        update(1,pos);
    }
    printf("%lld\n",ans);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值