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;
}