BZOJ2683: 简单题 kdtree

题目大意:n*n矩阵,单点加,矩形查和
1<=N<=500000,操作数不超过200000个,内存限制20M。
正解是cdq分治,强行拿kdtree卡了过去。
1.n是矩形大小,不是操作数量,不要被坑了
2.kdtree是空树直接返回0,否则就崩了
3.nth_element的写法是(begin,nth,end,comp),话说我之前那个崂山白花蛇草水错成那样都能过。。。
4.kdtree的重构遍历千万不能遍历前先清空左右儿子。。。
时限50秒,43秒成功进入最后一页,然而号称卡内存的这道题我只用了6124K

#include<cstdio>
#include<algorithm>
#include<cmath>
#define u size_t
using std::nth_element;
bool cmp;
struct pnt
{
    u pos[2];
    pnt(u a,u b){pos[0]=a,pos[1]=b;}
    inline u& operator [] (u x){return pos[x];}
    inline bool operator < (const pnt &p) const
    {return pos[0]<p.pos[0]&&pos[1]<p.pos[1];}
    inline bool operator == (const pnt &p) const
    {return pos[0]==p.pos[0]&&pos[1]==p.pos[1];}
    inline bool operator <= (const pnt &p) const
    {return pos[0]<=p.pos[0]&&pos[1]<=p.pos[1];}
};
inline void min(u &a,u b){if(b<a) a=b;}
inline void max(u &a,u b){if(a<b) a=b;}
inline void min(pnt &a,pnt &b){min(a[0],b[0]),min(a[1],b[1]);}
inline void max(pnt &a,pnt &b){max(a[0],b[0]),max(a[1],b[1]);}
struct node
{
    node *l,*r;
    pnt p,mn,mx;
    u v,sum,sz;
    node(const pnt &p,u v):l(0),r(0),p(p),mn(p),mx(p),v(v),sum(v),sz(1){}
    u getsum(pnt &__mn,pnt &__mx)
    {
        if(__mn<=mn&&mx<=__mx) return sum;
        if(__mn[0]>mx[0]||__mn[1]>mx[1]||__mx[0]<mn[0]||__mx[1]<mn[1]) return 0;
        u __sum=0;
        if(__mn<=p&&p<=__mx) __sum+=v;
        if(l) __sum+=l->getsum(__mn,__mx);
        if(r) __sum+=r->getsum(__mn,__mx);
        return __sum;
    }
    inline void reset()
    {
        l=r=0;
        mn=mx=p;
        sum=v;
        sz=1;
    }
    inline void* operator new(u)
    {
        static node *s,*t;
        static u size=sizeof(node)<<12;
        if(s==t) s=(node*)malloc(size),t=s+(1<<12);
        return s++;
    }
    inline void up()
    {
        mn=mx=p,sum=v,sz=1;
        if(l)
        {
            min(mn,l->mn),max(mx,l->mx);
            sum+=l->sum;
            sz+=l->sz;
        }
        if(r)
        {
            min(mn,r->mn),max(mx,r->mx);
            sum+=r->sum;
            sz+=r->sz;
        }
    }
}*ar[200001];
inline bool less(node *a,node *b){return a->p[cmp]<b->p[cmp];}
u top=0;
const double A=0.7,B=log(1.0/0.7);
struct kdtree
{
    node *rt;
    kdtree():rt(0){}
    bool insert(node*& x,node *y,u h=0,bool comp=0)
    {
        if(!x)
        {
            x=new node(*y);
            return h>log(rt->sz)/B;
        }
        if(x->p==y->p) return x->v+=y->v,x->sum+=y->v,0;
        cmp=comp;
        if(less(y,x))
        {
            bool kre=insert(x->l,y,h+1,!comp);
            x->up();
            if(kre) return x->l->sz>x->sz*A?rebuild(x,comp),0:1;
            return 0;
        }
        else
        {
            bool kre=insert(x->r,y,h+1,!comp);
            x->up();
            if(kre)return x->r->sz>x->sz*A?rebuild(x,comp),0:1;
            return 0;
        }
    }
    inline void insert(pnt p,u v)
    {
        node it(p,v);
        insert(rt,&it);
    }
    void tour(node *x)
    {
        if(!x) return;
        tour(x->l);
        ar[++top]=x;
        tour(x->r);
        x->reset();
    }
    void rebuild(node*& x,bool comp,u l,u r)
    {
        if(r<l) {x=0;return;}
        cmp=comp;
        u mid=l+r>>1;
        nth_element(ar+l,ar+mid,ar+r+1,less);
        x=ar[mid];
        rebuild(x->l,!comp,l,mid-1),rebuild(x->r,!comp,mid+1,r);
        x->up();
    }
    inline void rebuild(node*& x,bool comp)
    {
        top=0;
        tour(x);
        rebuild(x,comp,1,top);
    }
    inline u query(u x1,u y1,u x2,u y2)
    {
        if(!rt) return 0;
        pnt mn(x1,y1),mx(x2,y2);
        return rt->getsum(mn,mx);
    }
}tr;
u n,o,x,y,a,z,w;
int main()
{
    scanf("%u",&n);
    while(scanf("%u",&o)==1)
    {
        if(o==3) break;
        if(o==1)
        {
            scanf("%u%u%u",&x,&y,&a);
            tr.insert(pnt(x,y),a);
        }
        else
        {
            scanf("%u%u%u%u",&x,&y,&z,&w);
            printf("%u\n",tr.query(x,y,z,w));
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值