【BZOJ】2683: 简单题 -KD-tree

传送门:bzoj2683


题解

也可以用 cdq c d q 分治做,这里用的 KDtree K D − t r e e
每个点上记录一下所管辖子树 x,y x , y 的最大,最小值,以及总值,还有自己的点信息。
仿照替罪羊树,如果树太不平衡了直接暴力重构。
每次查询如果完整覆盖这个点子树,直接返回总值,如果完全无关,也直接返回0,否则先判断当前点再继续递归下去。


代码

#include<bits/stdc++.h>
#define gc getchar()
#define si isdigit(c)
#define lc t[k].ch[0]
#define rc t[k].ch[1]
#define mid (((l)+(r))>>1)
#define db double
using namespace std;
const int N=2e5+100,inf=0x7fffffff;
const db alp=0.77;

int n,op,rt,ans,cnt,sz[N],D;

struct P{
  int x[2],v;
  P(){}
  P(int X,int Y,int V){x[0]=X,x[1]=Y,v=V;}
}p[N],mi,mx;

bool operator <(const P&a,const P&b){return a.x[D]<b.x[D];}

struct Node{
  int x[2],y[2],val,ch[2];P pos;
  Node(){}
  Node(int Xa,int Xb,int Ya,int Yb,int Val,int LS,int RS,P ky)
  {x[0]=Xa,x[1]=Ya,y[0]=Xb,y[1]=Yb,val=Val,ch[0]=LS,ch[1]=RS,pos=ky;}
}t[N];

struct Pool{
    int que[N],top;
    Pool(){top=0;}
    inline int newnode(){
       int re;
       if(top) re=que[top--];
       else re=++cnt;
       sz[re]=1;return re;
    }
    inline void ins(int x){que[++top]=x;}
}Q;

char c;
inline int rd()
{
    c=gc;int x=0,f=1;
    for(;!si;c=gc) if(c=='-') f=-1;
    for(;si;c=gc) x=x*10+(c^48);
    return x*f;
}

inline void pushup(int k)
{
    t[k].val=t[k].pos.v+t[lc].val+t[rc].val;
    sz[k]=sz[lc]+sz[rc]+1;
    t[k].x[0]=min(t[k].pos.x[0],min(t[lc].x[0],t[rc].x[0]));
    t[k].x[1]=min(t[k].pos.x[1],min(t[lc].x[1],t[rc].x[1]));
    t[k].y[0]=max(t[k].pos.x[0],max(t[lc].y[0],t[rc].y[0]));
    t[k].y[1]=max(t[k].pos.x[1],max(t[lc].y[1],t[rc].y[1]));
}

inline void pai(int k,int num)
{
    if(lc) pai(lc,num);
    p[sz[lc]+num+1]=t[k].pos;Q.ins(k);
    if(rc) pai(rc,sz[lc]+num+1);
}

inline void build(int &k,int l,int r,int d)
{
    if(l>r) return;
    k=Q.newnode();
    D=d;nth_element(p+l,p+mid,p+r+1);
    t[k].pos=p[mid];lc=rc=0;
    build(lc,l,mid-1,d^1);build(rc,mid+1,r,d^1);
    pushup(k);
}

inline void check(int &k,int d)
{
    if(sz[k]*alp<sz[lc] || sz[k]*alp<sz[rc]){
        pai(k,0);build(k,1,sz[k],d);
    }
}

inline void ad(int &k,P pt,int d)
{
    if(!k) {
      k=Q.newnode();
      t[k]=Node(pt.x[0],pt.x[0],pt.x[1],pt.x[1],pt.v,0,0,pt);
      return;
    }
    if(pt.x[d]<=t[k].pos.x[d]) ad(lc,pt,d^1);
    else ad(rc,pt,d^1);
    pushup(k);check(k,d);
}

inline bool in(Node k)
{return (k.x[0]>=mi.x[0] && k.x[1]>=mi.x[1] && k.y[0]<=mx.x[0] && k.y[1]<=mx.x[1]);}
inline bool out(Node k)
{
    if(k.y[0]<mi.x[0] || k.x[0]>mx.x[0]) return true;
    if(k.y[1]<mi.x[1] || k.x[1]>mx.x[1]) return true;
    return false;
}

inline bool inn(P a)
{return (a.x[0]>=mi.x[0] && a.x[0]<=mx.x[0] && a.x[1]>=mi.x[1] && a.x[1]<=mx.x[1]);}

inline int query(int k)
{
    if(!k) return 0;
    if(in(t[k])) return t[k].val; 
    if(out(t[k])) return 0;
    int re=0;
    if(inn(t[k].pos)) re=t[k].pos.v;
    re+=query(lc)+query(rc);
    return re;
}

int main(){
    n=rd();
    t[0]=Node(inf,-inf,inf,-inf,0,0,0,P(0,0,0));
    for(;;){
        op=rd();
        if(op==3) break;
        if(op==1){
            mi.x[0]=rd();mi.x[1]=rd();mi.v=rd();
            ad(rt,mi,0);
        }else{
            mi.x[0]=rd();mi.x[1]=rd();mx.x[0]=rd();mx.x[1]=rd();
            printf("%d\n",ans=query(rt));
        } 
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值