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));
        }
}
原文地址:https://www.cnblogs.com/ditoly/p/20170331P.html