Poj2274[The Race]题解--逆序对&二叉堆

来源:互联网 发布:阿里云测试招聘 编辑:程序博客网 时间:2024/06/05 10:48

【题目大意】
本题的大意就是有n个飞船,给出飞船的位置和速度,求飞船之间超越的总次数(结果要mod 1000000)和两个互相超越的飞船的编号(按时间大小排序,如果超越的总次数大于10000则输出前10000个)

【解题报告】
求飞船之间超越的总次数逆序对即可。

两个互相超越的飞船的编号:
用小根堆来做,按照飞船x超越飞船y的时间的大小建堆。
每次从堆顶取出一组超越的编号,则先验证编号是否成立,成立便将这两艘飞船的实时位置交换,并判断交换后这两艘飞船是否可以超越相邻的飞船或被相邻的飞船超越,如果验证成功则将这组超越的编号放进堆中。

注:
1.实时位置为目前飞船所在的位置(即经过?次超越或被超越后,飞船所在的位置)
2.输出两个互相超越的飞船的编号中注意当超越的时间相同时,按照超越的飞船的实时位置从小到大排序,而不是初始位置。

#include<cstdio>#include<cstring>#include<algorithm>using namespace std;const int maxn=250005,maxm=10005,maxv=105,tt=1000000;int n,num,len,ans,max_v,c[maxv],where[maxn];struct wjd{    int x,y,id;}a[maxn];struct ha{    double x;    int s,t;}hep[maxn+maxm];inline int read_(){    int sum=0;    char ch=getchar();    while (ch<'0'||ch>'9') ch=getchar();    while (ch>='0'&&ch<='9') sum=sum*10+ch-48,ch=getchar();    return sum;}void put_(double x,int s,int t){    hep[++len].x=x; hep[len].s=s; hep[len].t=t; int son=len;    while (son!=1&&(hep[son].x<hep[son>>1].x||(hep[son].x==hep[son>>1].x&&where[hep[son].s]<where[hep[son>>1].s]))) swap(hep[son],hep[son>>1]),son>>=1; //按照超越时间为第一关键字,实时距离为第二关键字建小根堆}ha get_(){    ha sum=hep[1];    hep[1]=hep[len--];    int fa=1,son;    while (fa*2<=len)    {        if (fa*2+1>len||(hep[fa*2].x<hep[fa*2+1].x||(hep[fa*2].x==hep[fa*2+1].x&&where[hep[fa*2].s]<where[hep[fa*2+1].s]))) son=fa*2; else son=fa*2+1;        if (hep[son].x<hep[fa].x||(hep[son].x==hep[fa].x&&where[hep[son].s]<where[hep[fa].s]))        {            swap(hep[son],hep[fa]);            fa=son;        }        else break;    }    return sum;}int lowbit_(int x){    return x&(-x);}int get_(int x)//树状数组{    int sum=0;    while (x<=max_v)    {        sum+=c[x];        x+=lowbit_(x);    }    return sum;}void add_(int x,int da)//树状数组{    while (x>0)    {        c[x]+=da;        x-=lowbit_(x);    }}int main(){    freopen("2274.in","r",stdin);    freopen("2274.out","w",stdout);    n=read_(); len=ans=num=max_v=0;    for (int i=1; i<=n; i++) a[i].x=read_(),a[i].y=read_(),a[i].id=i,where[i]=i,max_v=max(max_v,a[i].y);    memset(c,0,sizeof(c));    for (int i=1; i<=n; i++) ans=(ans+get_(a[i].y))%tt,add_(a[i].y-1,1);//树状数组求逆序对    printf("%d\n",ans);    for (int i=1; i<n; i++)    {        if (a[i].y<=a[i+1].y) continue;        put_((double)(a[i+1].x-a[i].x)/(a[i].y-a[i+1].y),i,i+1);    }    num=0;    while (num<10000&&len!=0)    {        ha x=get_();        if ((where[x.s]+1!=where[x.t])) continue;//判断已经不存在的情况        printf("%d %d\n",x.s,x.t);        int s=where[x.s],t=where[x.t]; where[x.s]=t; where[x.t]=s;//记录实时位置        swap(a[s],a[t]);//将超越的两辆飞船交换位置        if (s>1&&(a[s-1].y>a[s].y)) if (where[a[s-1].id]+1==where[a[s].id]) put_((double)(a[s].x-a[s-1].x)/(a[s-1].y-a[s].y),a[s-1].id,a[s].id);        if (t<n&&(a[t].y>a[t+1].y)) if (where[a[t].id]+1==where[a[t+1].id]) put_((double)(a[t+1].x-a[t].x)/(a[t].y-a[t+1].y),a[t].id,a[t+1].id);//判断超越后是否与新的相邻的飞船产生超越情况        ++num;    }    return 0;}
1 0