【专题属性】堆

该博客主要介绍了如何利用堆解决坐标系中直线交点个数的问题。在初始设定中,有N条直线在点(0,Gi)与斜率Si相交,且Gi递增。目标是找到所有x<=T时的交点,并按照特定规则输出直线编号。通过将问题转化为求逆序对,可以利用树状数组或归并排序来解决。此外,博主还提出维护一个堆,以直线交点的横坐标和纵坐标作为key,通过堆操作更新交点信息。" 112570530,10536881,描述性统计:分组数据的统计与分析,"['统计学', '描述性统计', '数据汇总', '图表分析', '数值方法']
摘要由CSDN通过智能技术生成

KGold(UVALive 5868)


题目大意:

题目可以转换到坐标系上,初始的时候,有N条直线,直线的其中一点分别为(0,G1),(0,G2)...(0,Gn),且G1<G2<...<Gn,直线的斜率为S1,S2...Sn,G和S均为整数,问x<=T的交点个数,并且输出交点对应的两条直线的编号。假设交点为(idx,idy),先输出idx小的两条直线的编号,若idx相同,输出idy小的两条直线的编号。(数据满足不可能同时存在3条直线交于一点,1000000<=T<=2000000)


题解:

问1:求交点个数

T的下界为100W,易知T以后不会有交点,问题可以转换成求逆序对。(树状数组or归并均可)

问2:

维护一个堆,堆的key1是直线i与直线i+1交点的横坐标,key2是纵坐标。按key1和key2维护一个小根堆,每次弹出堆顶元素,则维护一下栈顶元素对应的rank以及rank-1,rank+1这3个点,因为只有这3个点会改变。


#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<ctime>
#include<algorithm>
#include<cmath>
#include<stack>
#include<queue>
#include<utility>
using namespace std;

#define INF 2140000000
#define maxn 500005
struct Node
{
    int id,g,s;
    bool operator <(const Node&o) const
    {
        return g>o.g;
    }
};

struct ST
{
    int rk;
    double nd,wh;
    bool operator <(const ST&o) const
    {
        if (nd==o.nd)
        return wh>o.wh;else
        return nd>o.nd;
    }
};

int hash_heap[maxn],n,pl[maxn],indx,bef[maxn];
ST heap[maxn];
Node node[maxn],node1[maxn];

void  swap_heap(int id1,int id2)
{
    hash_heap[heap[id1].rk]=id2;
    hash_heap[heap[id2].rk]=id1;
    ST tmp=heap[id1];
    heap[id1]=heap[id2];
    heap[id2]=tmp;
}

void heap_cg_up(int id , ST x)
{
    while (id/2>=1)
    {
        if (heap[id/2]<x)
        swap_heap(id/2,id);
        else break;
        id/=2;
    }
}

void heap_cg_dn(int id,ST x)
{
    while (id*2<=indx)
    {
        id=id*2;
        if (heap[id]<heap[id+1] && id<indx) id++;
        if (heap[id/2]<heap[id])
        swap_heap(id/2,id);
        else break;
    }
}


void heap_insert(int id,ST x)
{
    heap[id]=x;
    hash_heap[x.rk]=id;
    heap_cg_up(id,x);
}


ST setx(int id1,int id2)
{
    ST ans;
    if (id1==0 || node[id1].s>=node[id2].s)
    {
        ans.nd=INF;
        ans.wh=INF;
    }else
    {
        ans.nd=(node[id1].g-node[id2].g)*1.0/(node[id2].s-node[id1].s);
        ans.wh=node[id2].g+(node[id2].s-node[id1].s)*ans.nd;
    }
    ans.rk=id2;
    return ans;
}


int lowbit(int x)
{
    return x&(-x);
}

int add(int x,int pos)
{
    while (x<=n)
    {
        pl[x]=(pl[x]+pos+1000)%1000;
        x+=lowbit(x);
    }
}

int sum(int x)
{
    int tot=0;
    while (x>0)
    {
        tot=(tot+pl[x]+1000) %1000;
        x-=lowbit(x);
    }
    return tot;
}

int main()
{
	//freopen("in.txt","r",stdin);
	//freopen("out1.txt","w",stdout);
    int tt;
    scanf("%d",&tt);
    while (tt--)
    {
        int t;
        scanf("%d%d",&n,&t);
        for (int i=1;i<=n;i++)
        {
            int g,s;
            scanf("%d%d",&g,&s);
            node[i].id=i;
            node[i].g=g;
            node[i].s=s;
        }
        sort(node+1,node+n+1);

        for (int i=1;i<=n;i++)
        {
            node1[i].id=node[i].id;
            node1[i].g=node[i].g+t*node[i].s;
        }
        sort(node1+1,node1+n+1);

        memset(pl,0,sizeof(pl));
        for (int i=1;i<=n;i++)
        add(n-node1[i].id+1,1);

      //  cout<<sum(3)<<endl;

        int tot=0;
        for (int i=1;i<=n;i++)
        {
            tot=(tot+sum(n-node1[i].id))%1000;
            add(n-node1[i].id+1,-1);
        }


        printf("%d\n",tot);

       // heap_clear();

        indx=0;

        for (int i=1;i<=n;i++)
            heap_insert(++indx,setx(i-1,i));

        int cal=0;
        while (1)
        {
            cal++;
            if (cal>10000) break;
            ST x=heap[1];
            if (x.nd>t) break;

            swap_heap(1,indx);
            indx--;
            heap_cg_dn(1,heap[1]);
            printf("%d %d\n",node[x.rk].id,node[x.rk-1].id);

            Node tmp=node[x.rk];
            node[x.rk]=node[x.rk-1];
            node[x.rk-1]=tmp;

            int idx=hash_heap[x.rk-1];
            heap[idx].nd=INF;
            heap[idx].rk=x.rk;
            hash_heap[x.rk]=idx;
            heap_cg_dn(idx,heap[idx]);

            hash_heap[x.rk-1]=++indx;
            if (x.rk==2)
            {
                int idx=indx;
                heap[idx].nd=INF;
                heap[idx].rk=1;
                heap_insert(indx,heap[idx]);
            } else
            {
                int idx=indx;
                heap[idx]=setx(x.rk-2,x.rk-1);
                heap_insert(indx,heap[idx]);
               // heap_cg_dn(idx,heap[idx]);
            }



            if (x.rk<n)
            {
                int idx=hash_heap[x.rk+1];
                heap[idx]=setx(x.rk,x.rk+1);
                heap_cg_dn(idx,heap[idx]);
             //   idx=hash_heap[x.rk+1];
                heap_cg_up(idx,heap[idx]);
            }
        }

    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值