BZOJ4066: 简单题

5 篇文章 0 订阅
3 篇文章 0 订阅

50s卡过..不知道为什么这么慢


kdt模板题
格子(x,y)里的加A可以直接插入一个值为A的点(x,y),如果原来有这个点了也没关系
因为插入可能导致树不平衡,所以用替罪羊树的重构思想,不满足平衡条件时暴力重构子树

2017.12.29 upd: 感谢学弟的指正代码重构部分写错了,带进去的那个D不一定是0,改了之后真的快了挺多的qwq….

code:

#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;

const int maxn = 510000;
const int maxm = 200100;
const int maxd = 2;
const double A = 0.74;

inline int read()
{
    char c; int x;
    while(!((c=getchar())>='0'&&c<='9'));
    x=c-'0';
    while((c=getchar())>='0'&&c<='9') (x*=10)+=c-'0';
    return x;
}
inline void up(int &x,const int &y){if(x<y)x=y;}
inline void down(int &x,const int &y){if(x>y)x=y;}
struct KD_tree
{
    int pos[maxd],u[maxd],d[maxd];
    int c,s,siz,l,r,nowd;
}kd[maxm]; int root,tot;
int cmp_d;
inline bool cmp(const int &x,const int &y){return kd[x].pos[cmp_d]<kd[y].pos[cmp_d];}

int id[maxm],cnt;

inline void push_up(KD_tree &X)
{
    int lc=X.l,rc=X.r;
    if(lc)
    {
        up(X.u[0],kd[lc].u[0]); 
        up(X.u[1],kd[lc].u[1]);
        down(X.d[0],kd[lc].d[0]); 
        down(X.d[1],kd[lc].d[1]);
        X.c+=kd[lc].c;
        X.siz+=kd[lc].siz;
    }
    if(rc)
    {
        up(X.u[0],kd[rc].u[0]); 
        up(X.u[1],kd[rc].u[1]);
        down(X.d[0],kd[rc].d[0]); 
        down(X.d[1],kd[rc].d[1]);
        X.c+=kd[rc].c;
        X.siz+=kd[rc].siz;
    }
}
void dfs(int &x)
{
    if(kd[x].l) dfs(kd[x].l);
    id[++cnt]=x;
    if(kd[x].r) dfs(kd[x].r);
    x=0;
}
int build(const int &l,const int &r,int D)
{
    int mid=(l+r)>>1;
    cmp_d=D; nth_element(id+l,id+mid,id+r+1,cmp);
    int x=id[mid];
    KD_tree &X=kd[x];
    X.d[0]=X.u[0]=X.pos[0]; X.d[1]=X.u[1]=X.pos[1];
    X.c=X.s; X.siz=1; X.nowd=D;
    if(l!=mid) X.l=build(l,mid-1,!D);
    if(mid!=r) X.r=build(mid+1,r,!D);
    push_up(kd[x]);
    return x;
}
inline void rebuild(int &x)
{
    cnt=0; int nowd=kd[x].nowd;
    int tx=x; dfs(tx); x=build(1,cnt,nowd);
}
int *tmp,kt;
int pos[maxd];
void ins(int &x,const int &c,int D)
{
    if(!x)
    {
        KD_tree &t=kd[x=++tot];
        t.pos[0]=t.u[0]=t.d[0]=pos[0];
        t.pos[1]=t.u[1]=t.d[1]=pos[1];
        t.c=c; t.s=c; t.siz=1;
        t.nowd=D;
        tmp=&kt;
        return ;
    }
    KD_tree &t=kd[x];
    t.c+=c; t.siz++;
    up(t.u[0],pos[0]); up(t.u[1],pos[1]);
    down(t.d[0],pos[0]); down(t.d[1],pos[1]);
    if(pos[D]<=t.pos[D]) ins(t.l,c,!D);
    else ins(t.r,c,!D);
    if(kd[t.l].siz>t.siz*A||kd[t.r].siz>t.siz*A)
        tmp=&x;
}
int Ans;
int Pd[maxd],Pu[maxd];
void Query(const int &x)
{
    KD_tree &X=kd[x];
    if(X.d[0]>=Pd[0]&&X.d[1]>=Pd[1]&&X.u[0]<=Pu[0]&&X.u[1]<=Pu[1]) {Ans+=X.c; return;}
    if(X.u[0]<Pd[0]||X.u[1]<Pd[1]||X.d[0]>Pu[0]||X.d[1]>Pu[1]) return;
    if(X.pos[0]>=Pd[0]&&X.pos[1]>=Pd[1]&&X.pos[0]<=Pu[0]&&X.pos[1]<=Pu[1])
        Ans+=X.s;
    Query(X.l);
    Query(X.r);
}

int main()
{
    //freopen("tmp.in","r",stdin);
    //freopen("tmp.out","w",stdout);

    int n=read(); Ans=0;
    while(1)
    {
        int temp=read();
        if(temp==3) break;
        if(temp==1)
        {
            pos[0]=read()^Ans,pos[1]=read()^Ans;
            int c=read(); c^=Ans;
            ins(root,c,0);
            if((*tmp)) rebuild((*tmp));
        }
        else
        {
            Pd[0]=read()^Ans,Pd[1]=read()^Ans;
            Pu[0]=read()^Ans,Pu[1]=read()^Ans;
            Ans=0; Query(root);
            printf("%d\n",Ans);
        }
    }

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值