K-d树

前言
K-d树的K其实表示的是数据是几维的,所以我们一般用的都是2-d树。


2-d树原理
当数据有两维时,一般都是维护平面上的数据,我们无法想线段树那样一直缩小范围得到想要的区间,但是我们可以通过交错缩小横纵坐标来最终得到想要的平面,这就是2-d树的原理。


写法:
例子:简单题
题目大意:动态维护矩形内数字和
和大多数树形结构一样,我们一切操作都需要从根开始,维护当前的点代表的平面,知道这个平面是询问的一个子平面,直接返回结果,否则继续向下递归,要特别注意的地方是需要特判当前的点是否在询问的平面的,如果是的话还要加上这个点的值。

#include 
using namespace std;

const int maxm=2e5+1000;
const int inf=1e7;
int n,la,cntt;
bool nowp;

struct data
{
    int num,sum,c[2],minx,miny,maxx,maxy,x,y;
    friend bool operator < (data t1,data t2)
    {
        if(nowp) return t1.xelse return t1.ystruct kd_tree
{
    data t[maxm];
    int cnt,root;

    void insert(int &now,int sx,int sy,int num1,int p)
    {
        if(sx==t[now].x&&sy==t[now].y)
        {
            t[now].num+=num1;
            t[now].sum+=num1;
            return;
        }
        if(!now)
        {
            now=++cnt;
            if(!root) root=now;
            t[now].num=t[now].sum=num1;
            t[now].x=t[now].maxx=t[now].minx=sx;
            t[now].y=t[now].maxy=t[now].miny=sy;
            t[now].c[0]=t[now].c[1]=0;
            return;
        }
        t[now].maxx=max(t[now].maxx,sx);
        t[now].minx=min(t[now].minx,sx);
        t[now].maxy=max(t[now].maxy,sy);
        t[now].miny=min(t[now].miny,sy);
        t[now].sum+=num1;
        if(p)
        {
            if(sx<=t[now].x) insert(t[now].c[0],sx,sy,num1,!p);
            else insert(t[now].c[1],sx,sy,num1,!p);
        }
        else
        {
            if(sy<=t[now].y) insert(t[now].c[0],sx,sy,num1,!p);
            else insert(t[now].c[1],sx,sy,num1,!p);
        }
    }

    int query(int now,int hx,int lx,int hy,int ly)
    {
        if(!now) return 0;
        if(hxt[now].maxx||hyt[now].maxy) return 0;
        if(t[now].maxx<=hx&&t[now].minx>=lx&&t[now].maxy<=hy&&t[now].miny>=ly) return t[now].sum;
        int ans=0;
        if(t[now].x>=lx&&t[now].x<=hx&&t[now].y>=ly&&t[now].y<=hy) ans+=t[now].num;
        return ans+query(t[now].c[0],hx,lx,hy,ly)+query(t[now].c[1],hx,lx,hy,ly);
    }

    void rebuild(int &now,int l,int r,int p)
    {
        if(l>r) return;
        nowp=p;
        int mid=(l+r)>>1;
        nth_element(t+l,t+mid+1,t+r+1);
        now=mid;
        if(!root) root=mid;
        if(l==r)
        {
            t[mid].sum=t[mid].num;
            t[mid].maxx=t[mid].minx=t[mid].x;
            t[mid].maxy=t[mid].miny=t[mid].y;
            t[mid].c[0]=t[mid].c[1]=0;
            return;
        }
        rebuild(t[mid].c[0],l,mid-1,!p);
        rebuild(t[mid].c[1],mid+1,r,!p);
        t[mid].maxx=max(max(t[mid].c[0]?t[t[mid].c[0]].maxx:-inf,t[mid].c[1]?t[t[mid].c[1]].maxx:-inf),t[mid].x);
        t[mid].maxy=max(max(t[mid].c[0]?t[t[mid].c[0]].maxy:-inf,t[mid].c[1]?t[t[mid].c[1]].maxy:-inf),t[mid].y);
        t[mid].minx=min(min(t[mid].c[0]?t[t[mid].c[0]].minx:inf,t[mid].c[1]?t[t[mid].c[1]].minx:inf),t[mid].x);
        t[mid].miny=min(min(t[mid].c[0]?t[t[mid].c[0]].miny:inf,t[mid].c[1]?t[t[mid].c[1]].miny:inf),t[mid].y);
        t[mid].sum=t[t[mid].c[0]].sum+t[t[mid].c[1]].sum+t[mid].num;
    }

    void init()
    {
        root=0;
        for(int i=0;i<=cnt;i++) t[i].maxx=t[i].minx=t[i].maxy=t[i].miny=t[i].c[0]=t[i].c[1]=t[i].sum=0;
    }

}T;

int main()
{
    scanf("%d",&n);
    while(1)
    {
        cntt++;
        if(cntt%10000==0)
        {
            T.init();
            T.rebuild(n,1,T.cnt,1);
        }
        int type;
        scanf("%d",&type);
        if(type==1)
        {
            int x,y,num;
            scanf("%d%d%d",&x,&y,&num);
            x^=la;y^=la;num^=la;
            T.insert(T.root,x,y,num,1);
        }
        else if(type==2)
        {
            int sx,sy,ex,ey;
            scanf("%d%d%d%d",&sx,&sy,&ex,&ey);
            sx^=la;sy^=la;ex^=la;ey^=la;
            printf("%d\n",la=T.query(T.root,max(sx,ex),min(sx,ex),max(sy,ey),min(sy,ey)));
        }
        else break;
    }
    return 0;
}

你可能感兴趣的:(学习笔记,K-d树)