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;
    nth_element(t+l,t+mid,t+r+1);
    D^=1;t[mid].l=build(l,mid-1);D^=1;
    D^=1;t[mid].r=build(mid+1,r);D^=1;
    return 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);
}
时间: 2024-09-29 04:43:47

k-d tree模板练习的相关文章

POJ1442-查询第K大-Treap模板题

模板题,以后要学splay,大概看一下treap就好了. 1 #include <cstdio> 2 #include <algorithm> 3 #include <cstring> 4 5 using namespace std; 6 7 const int maxn = 3e5+10; 8 int num[maxn],st[maxn]; 9 10 struct Treap{ 11 int size; 12 int key,fix; 13 Treap *ch[2];

K短路【模板】

A*+SPFA算法: (1)将有向图的所有边正向.反向分别存入两个不同的边集(Edges,Edges1)中.用反向边集,以所求终点t为源点,利用SPFA或Dijkstra求解出所有点到t的最短路径,用Dist[i]数组来表示点i到点t的最短距离. (2)建立一个优先队列,将源点s加入到队列中. (3)从优先队列中取出最小的点p,如果点p == t,则计算t出队的次数.如果当前路径长度就是s到t的第k短路长度,算法结束.否则遍历与p相连的所有的边,将扩展出的到p的邻接点信息加入到优先队列中取. 注

Splay Tree 模板

1 /****************************************** 2 数据结构: 3 Splay_Tree,伸展树; 4 5 详见我的另一篇博客 http://www.cnblogs.com/wyj-jenny/p/5771561.html 6 7 性质: 8 伸展树是二叉查找树的一种改进; 9 与二叉查找树一样,伸展树也具有有序性; 10 即伸展树中的每一个节点x都满足: 11 该节点左子树中的每一个元素都小于x; 12 而其右子树中的每一个元素都大于x; 13 与普

Codeforces 600E - Lomsat gelral 「$Dsu \ on \ tree$模板」

With $Dsu \ on \ tree$ we can answer queries of this type: How many vertices in the subtree of vertex $v$ has some property in $O (n \log n)$ time (for all of the queries)? 这题写的是轻重儿子(重链剖分)版本的 $Dsu \ on \ tree$ 具体流程如下: 每次先递归计算轻儿子,再单独递归重儿子,计算完后轻儿子的一些信息

【BZOJ 3282】Tree Link Cut Tree模板题

知道了为什么要换根(changeroot),access后为什么有时要splay,以及LCT的其他操作,算是比较全面的啦吧,,, 现在才知道这些,,,真心弱,,, #include<cstdio> #include<algorithm> #define read(x) x=getint() using namespace std; const int N=300003; inline int getint(){char c;int ret=0;for(c=getchar();c&l

[模板]Link Cut Tree

传送门 Description 给定n个点以及每个点的权值,要你处理接下来的m个操作.操作有4种.操作从0到3编号.点从1到n编号. 0:后接两个整数(x,y),代表询问从x到y的路径上的点的权值的xor和.保证x到y是联通的. 1:后接两个整数(x,y),代表连接x到y,若x到y已经联通则无需连接. 2:后接两个整数(x,y),代表删除边(x,y),不保证边(x,y)存在. 3:后接两个整数(x,y),代表将点x上的权值变成y. Solution \(Link\ Cut\ Tree\)模板题

树状数组模板

看了很多讲解仍然不明就里,感觉反正代码很短,暂时当模板背过好了. //树状数组 单点修改 区间查询 const int maxn=1005; int tree[maxn],n; void init() { for (int i=1;i<=n;i++) tree[i]=0; } //初始化一个长度为n的树状数组,n为全局变量 int lowbit(it k) { return k&-k; } void add(int k,int x) //给位置k加x { while (k<=n) {

[模板]洛谷T3373 线段树 模板2

此题相对于模板一,加了个区间乘,于是在模板一的基础上需要多开个数组(记录乘法懒标记).多写个函数(区间乘),还有要把懒标记下放函数做些修改. 变量定义: sum[]:线段树节点对应区间的元素总和: addv[]:线段树节点对应区间的所有元素待加的值(懒标记),初值全部设为0: mulv[]:线段树节点对应区间的所有元素待乘的值(懒标记),初值全部设为1. 过程说明: 建树(Build): 同模板一... 懒标记下放(Push_down): 原理解释: 1.当对某区间执行加法操作时,由于加法优先级

线段树、KMP、HASH模板

线段树 #include<cstdio> using namespace std; int n,p,a,b,m,x,y,ans; struct node { int l,r,w,f; }tree[400001]; inline void build(int k,int ll,int rr)//建树 { tree[k].l=ll,tree[k].r=rr; if(tree[k].l==tree[k].r) { scanf("%d",&tree[k].w); retur