[JZOJ3989]Point

1 篇文章 0 订阅
1 篇文章 0 订阅

题目大意

给定第一象限上的 n 个点。之后依次给出m次操作。每次操作会给出两个参数 k,a ,然后删掉所有满足以下条件的点 (x,y)

y>kxa

每个点只会被删除一次。请你求出每个点是在第几次操作时被删除的。

0n,m105,0<xi,yi103,0<k106,0<a10


题目分析

这条式子里面有次幂,并且还是实数次幂,看起来十分恶心,我们给它两边取对数就能好看很多了:

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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值