• k-d tree模板练习


    1. [BZOJ]1941: [Sdoi2010]Hide and Seek

    题目大意:给出n个二维平面上的点,一个点的权值是它到其他点的最长距离减最短距离,距离为曼哈顿距离,求最小权值。(n<=500,000)

    思路:k-d tree裸题。

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    inline int read()
    {
        int x;char c;
        while((c=getchar())<'0'||c>'9');
        for(x=c-'0';(c=getchar())>='0'&&c<='9';)x=(x<<3)+(x<<1)+c-'0';
        return x;
    }
    #define MN 500000
    #define INF 0x7FFFFFFF
    int rt,D,q[2];
    struct node
    {
        int p[2],mn[2],mx[2],l,r;
        friend bool operator<(const node&a,const node&b){return a.p[D]<b.p[D];}
    }t[MN+5];
    void up(int k)
    {
        for(int l=t[k].l,r=t[k].r,i=0;i<2;++i)
            t[k].mn[i]=t[k].mx[i]=t[k].p[i],
            l?(t[k].mn[i]=min(t[k].mn[i],t[l].mn[i]),t[k].mx[i]=max(t[k].mx[i],t[l].mx[i])):0,
            r?(t[k].mn[i]=min(t[k].mn[i],t[r].mn[i]),t[k].mx[i]=max(t[k].mx[i],t[r].mx[i])):0;
    }
    int build(int l,int r)
    {
        if(l>r)return 0;
        int mid=l+r>>1;D^=1;
        nth_element(t+l,t+mid,t+r+1);
        t[mid].l=build(l,mid-1);
        t[mid].r=build(mid+1,r);
        return D^=1,up(mid),mid;
    }
    inline int calmx(int k)
    {
        return max(abs(q[0]-t[k].mn[0]),abs(t[k].mx[0]-q[0]))+
               max(abs(q[1]-t[k].mn[1]),abs(t[k].mx[1]-q[1]));
    }
    void qmx(int k)
    {
        D=max(D,abs(t[k].p[0]-q[0])+abs(t[k].p[1]-q[1]));
        int dl=t[k].l?calmx(t[k].l):-INF,dr=t[k].r?calmx(t[k].r):-INF;
        if(dl>dr){if(dl>D)qmx(t[k].l);if(dr>D)qmx(t[k].r);}
             else{if(dr>D)qmx(t[k].r);if(dl>D)qmx(t[k].l);}
    }
    inline int calmn(int k)
    {
        return max(t[k].mn[0]-q[0],0)+max(q[0]-t[k].mx[0],0)+
               max(t[k].mn[1]-q[1],0)+max(q[1]-t[k].mx[1],0);
    }
    void qmn(int k)
    {
        int x=abs(t[k].p[0]-q[0])+abs(t[k].p[1]-q[1]);if(x)D=min(D,x);
        int dl=t[k].l?calmn(t[k].l):INF,dr=t[k].r?calmn(t[k].r):INF;
        if(dl<dr){if(dl<D)qmn(t[k].l);if(dr<D)qmn(t[k].r);}
             else{if(dr<D)qmn(t[k].r);if(dl<D)qmn(t[k].l);}
    }
    int main()
    {
        int n=read(),i,x,ans=INF;
        for(i=1;i<=n;++i)t[i].p[0]=read(),t[i].p[1]=read();
        rt=build(1,n);
        for(i=1;i<=n;++i)
        {
            q[0]=t[i].p[0];q[1]=t[i].p[1];
            D=-INF;qmx(rt);x=D;
            D=INF;qmn(rt);
            ans=min(ans,x-D);
        }
        printf("%d",ans);
    }

    2. [BZOJ]2648: SJY摆棋子

    题目大意:一开始有n个黑棋,m次操作,每次多摆一个黑棋或者摆上一个白棋并询问离这个白棋最近的黑棋的距离,距离为曼哈顿距离。(n,m<=500,000)

    思路:k-d tree裸题,暴力插点可过,也可以分块重构。

    暴力插

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    inline int read()
    {
        int x;char c;
        while((c=getchar())<'0'||c>'9');
        for(x=c-'0';(c=getchar())>='0'&&c<='9';)x=(x<<3)+(x<<1)+c-'0';
        return x;
    }
    #define MN 1000000
    #define INF 0x7FFFFFFF
    int rt,D,q[2];
    struct node
    {
        int p[2],mn[2],mx[2],l,r;
        friend bool operator<(const node&a,const node&b){return a.p[D]<b.p[D];}
    }t[MN+5];
    inline void up(int k)
    {
        for(int l=t[k].l,r=t[k].r,i=0;i<2;++i)
            t[k].mn[i]=t[k].mx[i]=t[k].p[i],
            l?(t[k].mn[i]=min(t[k].mn[i],t[l].mn[i]),t[k].mx[i]=max(t[k].mx[i],t[l].mx[i])):0,
            r?(t[k].mn[i]=min(t[k].mn[i],t[r].mn[i]),t[k].mx[i]=max(t[k].mx[i],t[r].mx[i])):0;
    }
    int build(int l,int r)
    {
        if(l>r)return 0;
        int mid=l+r>>1;D^=1;
        nth_element(t+l,t+mid,t+r+1);
        t[mid].l=build(l,mid-1);
        t[mid].r=build(mid+1,r);
        return D^=1,up(mid),mid;
    }
    void ins(int&k,int x){k?(D^=1,ins(t[x]<t[k]?t[k].l:t[k].r,x),0):(k=x,0);up(k);}
    inline int cal(int k)
    {
        return k?max(t[k].mn[0]-q[0],0)+max(q[0]-t[k].mx[0],0)+
                 max(t[k].mn[1]-q[1],0)+max(q[1]-t[k].mx[1],0):INF;
    }
    void query(int k)
    {
        D=min(D,abs(t[k].p[0]-q[0])+abs(t[k].p[1]-q[1]));
        int dl=cal(t[k].l),dr=cal(t[k].r);
        if(dl<dr){if(dl<D)query(t[k].l);if(dr<D)query(t[k].r);}
             else{if(dr<D)query(t[k].r);if(dl<D)query(t[k].l);}
    }
    int main()
    {
        int n,m,i;
        n=read();m=read();
        for(i=1;i<=n;++i)t[i].p[0]=read(),t[i].p[1]=read();
        rt=build(1,n);
        while(m--)read()<2?
            (t[++n].p[0]=read(),t[n].p[1]=read(),D=0,ins(rt,n),0):
            (q[0]=read(),q[1]=read(),D=INF,query(rt),printf("%d
    ",D));
    }

     替罪羊重构版,貌似比暴力还慢……

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    inline int read()
    {
        int x;char c;
        while((c=getchar())<'0'||c>'9');
        for(x=c-'0';(c=getchar())>='0'&&c<='9';)x=(x<<3)+(x<<1)+c-'0';
        return x;
    }
    #define MN 1000000
    #define INF 0x7FFFFFFF
    #define alpha 0.75
    int rt,D,q[2],rD,*rb,rq[MN+5],qn;
    struct node
    {
        int p[2],mn[2],mx[2],l,r,s;
        friend bool operator<(const node&a,const node&b){return a.p[D]<b.p[D];}
    }t[MN+5];
    inline void up(int k)
    {
        t[k].s=t[t[k].l].s+t[t[k].r].s+1;
        for(int l=t[k].l,r=t[k].r,i=0;i<2;++i)
            t[k].mn[i]=t[k].mx[i]=t[k].p[i],
            l?(t[k].mn[i]=min(t[k].mn[i],t[l].mn[i]),t[k].mx[i]=max(t[k].mx[i],t[l].mx[i])):0,
            r?(t[k].mn[i]=min(t[k].mn[i],t[r].mn[i]),t[k].mx[i]=max(t[k].mx[i],t[r].mx[i])):0;
    }
    void get(int k)
    {
        if(!k)return;
        rq[++qn]=k;
        get(t[k].l);get(t[k].r);
    }
    bool cmp(int a,int b){return t[a]<t[b];}
    int build(int l,int r)
    {
        if(l>r)return 0;
        int mid=l+r>>1;D^=1;
        nth_element(rq+l,rq+mid,rq+r+1,cmp);
        t[rq[mid]].l=build(l,mid-1);
        t[rq[mid]].r=build(mid+1,r);
        return D^=1,up(rq[mid]),rq[mid];
    }
    void ins(int&k,int x)
    {
        D^=1;k?(ins(t[x]<t[k]?t[k].l:t[k].r,x),0):(k=x,0);up(k);D^=1;
        if(t[t[x].l].s>t[x].s*alpha||t[t[x].r].s>t[x].s*alpha)rb=&k,rD=D;
    }
    inline int cal(int k)
    {
        return k?max(t[k].mn[0]-q[0],0)+max(q[0]-t[k].mx[0],0)+
                 max(t[k].mn[1]-q[1],0)+max(q[1]-t[k].mx[1],0):INF;
    }
    void query(int k)
    {
        D=min(D,abs(t[k].p[0]-q[0])+abs(t[k].p[1]-q[1]));
        int dl=cal(t[k].l),dr=cal(t[k].r);
        if(dl<dr){if(dl<D)query(t[k].l);if(dr<D)query(t[k].r);}
             else{if(dr<D)query(t[k].r);if(dl<D)query(t[k].l);}
    }
    int main()
    {
        int n,m,i;
        n=read();m=read();
        for(i=1;i<=n;++i)t[i].p[0]=read(),t[i].p[1]=read(),rq[i]=i;
        rt=build(1,n);
        while(m--)read()<2?
            (t[++n].p[0]=read(),t[n].p[1]=read(),D=0,rb=0,ins(rt,n),rb?(qn=0,get(*rb),D=rD,*rb=build(1,qn),0):0):
            (q[0]=read(),q[1]=read(),D=INF,query(rt),printf("%d
    ",D));
    }

    3. [BZOJ]4066: 简单题

    题目大意:一个n*n的矩阵,一开始元素均为0,每次使一个元素加上一个值或者查询一个子矩阵内元素和,强制在线,内存限制20MB。(n<=500,000,操作数<=200,000)

    思路:cdq和线段树都被封死了,用k-d tree分块重构乱暴力,复杂度O(能过)。

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    inline int read()
    {
        int x;char c;
        while((c=getchar())<'0'||c>'9');
        for(x=c-'0';(c=getchar())>='0'&&c<='9';)x=(x<<3)+(x<<1)+c-'0';
        return x;
    }
    #define MN 200000
    #define INF 0x7FFFFFFF
    int rt,D,mn[2],mx[2];
    struct node
    {
        int p[2],w,mn[2],mx[2],l,r,s;
        friend bool operator<(const node&a,const node&b){return a.p[D]<b.p[D];}
    }t[MN+5];
    inline void up(int k)
    {
        t[k].s=t[t[k].l].s+t[t[k].r].s+t[k].w;
        for(int l=t[k].l,r=t[k].r,i=0;i<2;++i)
            t[k].mn[i]=t[k].mx[i]=t[k].p[i],
            l?(t[k].mn[i]=min(t[k].mn[i],t[l].mn[i]),t[k].mx[i]=max(t[k].mx[i],t[l].mx[i])):0,
            r?(t[k].mn[i]=min(t[k].mn[i],t[r].mn[i]),t[k].mx[i]=max(t[k].mx[i],t[r].mx[i])):0;
    }
    int build(int l,int r)
    {
        if(l>r)return 0;
        int mid=l+r>>1;D^=1;
        nth_element(t+l,t+mid,t+r+1);
        t[mid].l=build(l,mid-1);
        t[mid].r=build(mid+1,r);
        return D^=1,up(mid),mid;
    }
    void ins(int&k,int x){D^=1;k?(ins(t[x]<t[k]?t[k].l:t[k].r,x),0):(k=x,0);up(k);}
    inline bool in(int k)
    {
        return mn[0]<=t[k].mn[0]&&t[k].mx[0]<=mx[0]&&
               mn[1]<=t[k].mn[1]&&t[k].mx[1]<=mx[1];
    }
    inline bool pin(int k)
    {
        return mn[0]<=t[k].p[0]&&t[k].p[0]<=mx[0]&&
               mn[1]<=t[k].p[1]&&t[k].p[1]<=mx[1];
    }
    inline bool out(int k)
    {
        return mx[0]<t[k].mn[0]||mn[0]>t[k].mx[0]||
               mx[1]<t[k].mn[1]||mn[1]>t[k].mx[1];
    }
    int query(int k)
    {
        return !k||out(k)?0:in(k)?t[k].s:(pin(k)?t[k].w:0)+query(t[k].l)+query(t[k].r);
    }
    int main()
    {
        int n=0,l=0,p;read();
        while((p=read())<3)
            if(p<2)
            {
                t[++n].p[0]=read()^l;t[n].p[1]=read()^l;t[n].w=read()^l;
                D=0;t[rt].s%10000?(ins(rt,n),0):rt=build(1,n);
            }
            else
            {
                mn[0]=read()^l;mn[1]=read()^l;
                mx[0]=read()^l;mx[1]=read()^l;
                printf("%d
    ",l=query(rt));
            }
    }
  • 相关阅读:
    js string format All In One
    CSS water wave effect All In One
    Github PR 时合并多次提交的 git commits All In One
    js auto selector dom by providing id All In One
    JSS All In One
    python 中将fastq文件保存为字典
    python 中统计fasta文件中每条序列的长度
    c语言中利用do while循环语句限制用户的输入范围
    python中记录程序运行时间
    c语言中的do while循环语句
  • 原文地址:https://www.cnblogs.com/ditoly/p/20170331P.html
Copyright © 2020-2023  润新知