题目大意
给定第一象限上的
n
个点。之后依次给出
y>kxa
每个点只会被删除一次。请你求出每个点是在第几次操作时被删除的。
0≤n,m≤105,0<xi,yi≤103,0<k≤106,0<a≤10
题目分析
这条式子里面有次幂,并且还是实数次幂,看起来十分恶心,我们给它两边取对数就能好看很多了:
algx+lgy>lgk
然后发现我们将 (lgx,lgy) 看成一个点,这条式子表示的就是一个半平面。那么我们每次操作就相当于每次删掉一个半平面内所有的点。
那么这个怎么弄呢?你可以使用整体二分+半平面交来做到 O(nlog2n) ,也可以使用其他奇怪的方法做到 O(nlogn) ,反正这里我打的是kd树。
和 [JZOJ3399] [BZOJ2850]巧克力王国一样的做法,在kd树中对半平面打标记,打完后全部下传就好了。注意这里一个点如果打过了标记,后来的标记不会更优,因此我们如果走到了一个有标记的节点,我们就可以直接退出了。
至于时间复杂度,参考kd树正交区域查询的时间复杂度上界计算方法,计算任意一条直线最多和多少个子区域相交:
Q(n)={O(1),O(1)+3Q(⌊n4⌋),n=1n>1
算出来单次修改复杂度大概是 O(3log4n) 。
这样看起来会超时,但是我们不管这么多~反正这个上界基本上很难达到~
反正跑起来飞快就是了
代码实现
注意判断浮点数大小关系一定要使用自己编写的特判函数判断EPS,不然会出现 x<y 但是 x>y 的鬼畜情况!!!
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cctype>
#include <cmath>
#define LC(x) son[x][0]
#define RC(x) son[x][1]
using namespace std;
typedef double db;
int buf[30];
inline void write(int x)
{
if (x<0) putchar('-'),x=-x;
for (;x;x/=10) buf[++buf[0]]=x%10;
if (!buf[0]) buf[++buf[0]]=0;
for (;buf[0];putchar('0'+buf[buf[0]--]));
}
const db EPS=1e-7;
const db INF=1e+30;
const int N=100050;
bool equ(db x,db y){return fabs(x-y)<=EPS;}
int sgn(db x){return equ(x,0.0)?0:(x<0?-1:1);}
struct P
{
db x,y;
P(db x_=0,db y_=0){x=x_,y=y_;}
}pts[N];
bool cmpx(int a,int b){return sgn(pts[a].x-pts[b].x)<0||equ(pts[a].x,pts[b].x)&&a<b;}
bool cmpy(int a,int b){return sgn(pts[a].y-pts[b].y)<0||equ(pts[a].y,pts[b].y)&&a<b;}
int srt[2][N],bin[N],opt[N];
int n,m,cnt1,cnt2;
db k,a;
struct KDtree
{
int son[N][2],tag[N],v[N],id[N];
db mi[N][2],mx[N][2];
int root,tot;
int newnode()
{
++tot;
son[tot][0]=son[tot][1]=0;
tag[tot]=v[tot]=m+1,id[tot]=0;
mi[tot][0]=mi[tot][1]=INF,mx[tot][0]=mx[tot][1]=-INF;
return tot;
}
void init(){tot=-1,newnode();}
void update(int x)
{
mi[x][0]=mx[x][0]=pts[id[x]].x,mi[x][1]=mx[x][1]=pts[id[x]].y;
for (int i=0;i<2;i++) mi[x][i]=min(mi[x][i],min(mi[LC(x)][i],mi[RC(x)][i])),mx[x][i]=max(mx[x][i],max(mx[LC(x)][i],mx[RC(x)][i]));
}
void build(int &rt,int l,int r,bool d)
{
if (l>r) return;
int mid=l+r>>1;
id[rt=newnode()]=srt[d][mid];
cnt1=cnt2=0;
int pl=0;
for (int i=l;i<=r;i++)
if (srt[d^1][i]!=srt[d][mid])
{
if (d?cmpy(srt[d^1][i],srt[d][mid]):cmpx(srt[d^1][i],srt[d][mid])) bin[l+(cnt1++)]=srt[d^1][i];
else bin[mid+(++cnt2)]=srt[d^1][i];
}
bin[mid]=srt[d][mid];
memcpy(srt[d^1]+l,bin+l,(r-l+1)*sizeof(int));
build(LC(rt),l,mid-1,d^1),build(RC(rt),mid+1,r,d^1);
update(rt);
}
bool in(P p){return sgn(a*p.x+p.y-k)>0;}
int calc(int x){return in(P(mi[x][0],mi[x][1]))+in(P(mi[x][0],mx[x][1]))+in(P(mx[x][0],mi[x][1]))+in(P(mx[x][0],mx[x][1]));}
void modify(int rt,int y)
{
if (tag[rt]!=m+1) return;
if (in(pts[id[rt]])&&v[rt]==m+1) v[rt]=y;
if (LC(rt))
{
int f=calc(LC(rt));
if (f)
{
if (f!=4) modify(LC(rt),y);
else if (tag[LC(rt)]==m+1) tag[LC(rt)]=y;
}
}
if (RC(rt))
{
int f=calc(RC(rt));
if (f)
{
if (f!=4) modify(RC(rt),y);
else if (tag[RC(rt)]==m+1) tag[RC(rt)]=y;
}
}
}
void download(int x)
{
if (LC(x))
{
if (tag[LC(x)]==m+1) tag[LC(x)]=tag[x];
download(LC(x));
}
if (RC(x))
{
if (tag[RC(x)]==m+1) tag[RC(x)]=tag[x];
download(RC(x));
}
v[x]=min(v[x],tag[x]);
opt[id[x]]=v[x]==m+1?-1:v[x];
}
}t;
int main()
{
freopen("point.in","r",stdin),freopen("point.out","w",stdout);
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++) scanf("%lf%lf",&pts[i].x,&pts[i].y),pts[i].x=log(pts[i].x),pts[i].y=log(pts[i].y);
for (int i=1;i<=n;i++) srt[0][i]=srt[1][i]=i;
sort(srt[0]+1,srt[0]+1+n,cmpx),sort(srt[1]+1,srt[1]+1+n,cmpy);
t.init(),t.build(t.root,1,n,0);
for (int i=1;i<=m;i++)
{
scanf("%lf%lf",&k,&a),k=log(k);
t.modify(t.root,i);
}
t.download(t.root);
for (int i=1;i<=n;i++) write(opt[i]),putchar('\n');
fclose(stdin),fclose(stdout);
return 0;
}