bzoj4605: 崂山白花蛇草水 //替罪羊式重构k-d树

bzoj4605: 崂山白花蛇草水


题意

Q(<=100000)次操作,支持:
在二维平面上插入一个坐标(x,y)(x,y<=500000),点权为v(<=1e9)的点;
查询矩形区域内第K大点权。
强制在线。


题解

今天neither问我在做什么题,我说是一个kdt模板题
双log的话空间似乎会炸?
所以就线段树套KDT了。
对于插入操作,我们把一个点插到权值线段树上对应的log棵KDT里。因为带插入KDT需要替罪羊式重构来保证平衡,所以单次复杂度log^2。
对于查询操作…直接在线段树上一路查下去就可以,单次复杂度是根号*log的。
这个整体复杂度是 O(nlog2n(log2n+n)) O ( n log 2 ⁡ n ( log 2 ⁡ n + n ) )
怎么看都会炸,但是可以过(笑


代码

为什么我 跑得 这 么 慢
↑然后发现自己每篇题解里几乎都出现了这句话。。
我自带巨大常数 QAQ

#include<bits/stdc++.h>
#define N 100005
#define V 3000005
using namespace std;
char ch;
int lans;
inline void rd(int &x)
{
    x=0;
    while((ch=getchar()-'0')<0|ch>9);
    for(;ch>-1&ch<10;x=(x<<3)+
    (x<<1)+ch,ch=getchar()-'0');
    x^=lans;
}
int q,l,r,mid,i,k,rt[V],C[2][V],Cnt=1,
c[2][V],xx[2][V],mx[2][V],mn[2][V],sz[V],cnt,
op,p,X[2],x2,y2,st[N],nxt[N],t;
bool dir[V];
void Del(int &x)
{
    if(!x)return;
    st[++t]=x;
    Del(c[0][x]),Del(c[1][x]),x=0;
}
bool cmp(int x,int y)
{return xx[t][x]<xx[t][y];}
int reb(int L,int R,bool mode)
{
    int Mid=L+R>>1,ret;
    t=(mode^=1);
    nth_element(st+L,st+Mid,st+R+1,cmp);
    dir[ret=st[Mid]]=mode,sz[ret]=R-L+1;
    for(int j=0;j<2;j++)
    mn[j][ret]=mx[j][ret]=xx[j][ret];
    if(L<Mid)
    c[0][ret]=reb(L,Mid-1,mode);
    if(Mid<R)
    c[1][ret]=reb(Mid+1,R,mode);
    for(int m=0;m<2;m++)
    for(int j=0;j<2;j++)
    if(c[m][ret])
    mn[j][ret]=mn[j][mn[j][ret]<mn[j][c[m][ret]]?ret:c[m][ret]],
    mx[j][ret]=mx[j][mx[j][ret]>mx[j][c[m][ret]]?ret:c[m][ret]];
    return ret;
}
int qry(int x)
{
    if(!x)return 0;
    if(X[0]<=mn[0][x]&&X[1]<=mn[1][x]&&mx[0][x]<=x2&&mx[1][x]<=y2)
    return sz[x];
    return (X[0]<=xx[0][x]&&X[1]<=xx[1][x]&&x2>=xx[0][x]&&y2>=xx[1][x])+
    (X[dir[x]]>mx[dir[x]][c[0][x]]?0:qry(c[0][x]))+
    ((dir[x]?y2:x2)<mn[dir[x]][c[1][x]]?0:qry(c[1][x]));
}
int main()
{
    rd(q),rd(q);
    while(q--)
    {
        rd(op),op^=lans;
        rd(X[0]),rd(X[1]);
        l=1,r=1e9;
        if(op<2)
        {
            rd(k),p=1;
            for(;;)
            {
                sz[++cnt]=1;
                for(int j=0;j<2;j++)
                mn[j][cnt]=mx[j][cnt]=xx[j][cnt]=X[j];
                if(i=rt[p])
                {
                    y2=0;
                    qwq:
                    sz[i]++,x2=X[dir[i]]>xx[dir[i]][i];
                    for(int j=0;j<2;j++)
                    mn[j][i]=mn[j][i]<X[j]?mn[j][i]:X[j],
                    mx[j][i]=mx[j][i]>X[j]?mx[j][i]:X[j];
                    if(!c[x2][i])c[x2][i]=cnt,dir[cnt]=dir[i]^1;
                    else if(c[x2][i][sz]+1<<2>sz[i]*3)
                    st[t=1]=cnt,Del(x2=i),
                    y2?c[c[1][y2]==i][y2]=reb(1,t,dir[y2]):(rt[p]=reb(1,t,1));
                    else
                    {
                        i=c[x2][y2=i];
                        goto qwq;
                    }
                }
                else rt[p]=cnt;
                if(l==r)break;
                (x2=(mid=l+r>>1)<k)?l=mid+1:r=mid;
                p=C[x2][p]=C[x2][p]?C[x2][p]:++Cnt;
            }
        }
        else
        {
            rd(x2),rd(y2),rd(k);
            if((i=qry(rt[p=1]))<k)
            lans=0,puts("NAIVE!ORZzyz.");
            else
            {
                while(l<r)
                {
                    mid=l+r>>1;
                    (i=qry(rt[C[1][p]]))<k?
                    r=mid,k-=i,p=C[0][p]:(l=mid+1,p=C[1][p]);
                }
                printf("%d\n",lans=l);
            }
        }
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值