【BZOJ 2716/2648】 [Violet 3]天使玩偶

2716: [Violet 3]天使玩偶

kd-tree模板题。

①首先依次按照每一维(即先按照x,再按照y,再按照x…多维同理)将点存在一棵二叉树中:

先求出以当前维数为关键字的中间点是谁(用到nth_element这个函数,可以直接把排名为k的放在第k位上,不保证其他有序:nth_element(a+1,a+1+k,a+1+n,cmp))

为了一会儿查询中求估价函数方便,需要记录一下当前节点的子树中各维的极值(max,min)

②插入操作与splay的插入操作同理。

③询问操作的本质是搜索+用估价函数剪枝(估价函数的结果一定比实际最优解小),先搜索更优的,用更优的那个子树更新答案;判断次优的子树的估价函数是否小于当前答案,可以发现这个概率是比较小的,进入次优子树搜索的概率就小一些。

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#define inf 0x3f3f3f3f
#define M 2000005
using namespace std;
int k,x[2],root,ans,now,n,m;
struct node
{
    int ma[2],mi[2],d[2],l,r;
}t[M];
void read(int &tmp)
{
    tmp=0;
    char ch=getchar();
    int fu=1;
    for (;ch<‘0‘||ch>‘9‘;ch=getchar())
        if (ch==‘-‘) fu=-1;
    for (;ch>=‘0‘&&ch<=‘9‘;ch=getchar())
        tmp=tmp*10+ch-‘0‘;
    tmp*=fu;
}
bool cmp(node a,node b)
{
    if (a.d[now]==b.d[now])
        return a.d[now^1]<b.d[now^1];
    return a.d[now]<b.d[now];
}
void Update(int x)
{
    int l=t[x].l,r=t[x].r;
    for (int i=0;i<2;i++)
    {
        t[x].ma[i]=max(t[x].ma[i],max(t[l].ma[i],t[r].ma[i]));
        t[x].mi[i]=min(t[x].mi[i],min(t[l].mi[i],t[r].mi[i]));
    }
}
int Build(int l,int r,int k)
{
    int m=(l+r)>>1;
    now=k;
    nth_element(t+l+1,t+m+1,t+r+1,cmp);
    for (int i=0;i<2;i++)
        t[m].ma[i]=t[m].mi[i]=t[m].d[i];
    if (l!=m)
        t[m].l=Build(l,m-1,k^1);
    if (r!=m)
        t[m].r=Build(m+1,r,k^1);
    Update(m);
    return m;
}
void Insert(int now)
{
    int k=0,p=root;
    while (1)
    {
        for (int i=0;i<2;i++)
        {
            t[p].ma[i]=max(t[p].ma[i],t[now].ma[i]);
            t[p].mi[i]=min(t[p].mi[i],t[now].mi[i]);
        }
        if (t[now].d[k]>=t[p].d[k])
        {
            if (!t[p].r)
            {
                t[p].r=now;
                return;
            }
            else p=t[p].r;
        }
        else
        {
            if (!t[p].l)
            {
                t[p].l=now;
                return;
            }
            else p=t[p].l;
        }
        k=k^1;
    }
}
int Dis(int p)
{
    return abs(t[p].d[0]-x[0])+abs(t[p].d[1]-x[1]);
}
int Get(int p)
{
    int ans=0;
    for (int i=0;i<2;i++)
        ans+=max(0,t[p].mi[i]-x[i])+max(0,x[i]-t[p].ma[i]);
    return ans;
}
void Query(int p)
{
    if (!p) return;
    int d0=Dis(p),dl=Get(t[p].l),dr=Get(t[p].r);
    if (d0<ans) ans=d0;
    if (dl<dr)
    {
        if (dl<ans) Query(t[p].l);
        if (dr<ans) Query(t[p].r);
    }
    else
    {
        if (dr<ans) Query(t[p].r);
        if (dl<ans) Query(t[p].l);
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    t[0].ma[0]=t[0].ma[1]=-inf,t[0].mi[0]=t[0].mi[1]=inf;
    for (int i=1;i<=n;i++)
        read(t[i].d[0]),read(t[i].d[1]);
    root=Build(1,n,0);
    for (int i=1;i<=m;i++)
    {
        read(k),read(x[0]),read(x[1]);
        if (k==1)
        {
            n++;
            for (int j=0;j<2;j++)
                t[n].ma[j]=t[n].mi[j]=t[n].d[j]=x[j];
            Insert(n);
        }
        else
        {
            ans=inf;
            Query(root);
            printf("%d",ans);
            putchar(‘\n‘);
        }
    }
    return 0;
}

时间: 2024-10-22 07:30:04

【BZOJ 2716/2648】 [Violet 3]天使玩偶的相关文章

【bzoj 2716】[Violet 3]天使玩偶 (CDQ+树状数组)

题目描述 Ayu 在七年前曾经收到过一个天使玩偶,当时她把它当作时间囊埋在了地下.而七年后 的今天,Ayu 却忘了她把天使玩偶埋在了哪里,所以她决定仅凭一点模糊的记忆来寻找它. 我们把 Ayu 生活的小镇看作一个二维平面坐标系,而 Ayu 会不定时地记起可能在某个点 (xmy) 埋下了天使玩偶:或者 Ayu 会询问你,假如她在 (x,y) ,那么她离近的天使玩偶可能埋下的地方有多远. 因为 Ayu 只会沿着平行坐标轴的方向来行动,所以在这个问题里我们定义两个点之间的距离为dist(A,B)=|A

SJY摆棋子&amp;&amp;[Violet 3]天使玩偶

SJY摆棋子 https://www.lydsy.com/JudgeOnline/problem.php?id=2648 [Violet 3]天使玩偶 https://www.lydsy.com/JudgeOnline/problem.php?id=2716 参考博客:https://blog.csdn.net/Littlewhite520/article/details/78284697 KDtree模板题,带插入 1 #include<iostream> 2 #include<cst

BZOJ 2716: [Violet 3]天使玩偶

2716: [Violet 3]天使玩偶 Time Limit: 80 Sec  Memory Limit: 128 MBSubmit: 1473  Solved: 621[Submit][Status][Discuss] Description Input Output Sample Input & Output 样例过大,略 HINT Source Vani原创 欢迎移步 OJ2648 [Submit][Status][Discuss] CDQ分治,分类讨论拆绝对值的方式,分别查询最优值.

BZOJ 2648 SJY摆棋子 / 2716 Violet 3 天使玩偶 K-D树

题目大意:平面上有一些点,问一个点周围离它最近的点的曼哈顿距离是多少.支持动态加点. 思路:CDQ分治可以离线解决,但是SJY是卡CDQ的,天使玩偶可以过.毕竟K-D树的O(sqrt(n))的时间复杂度摆在那. K-D树理解起来其实不难,有k个维度的时候,每一层按照一个维度排序,取出按照这个维度排序的中位数,当作这个块的根,然后将这个块分开.还有一个比较重要的东西就是估价函数,这个函数根据不同的题可能不同.股价函数的主要用途就是对搜索进行剪枝,如果估价函数就已经大于当前的最优答案了,那就不用搜这

【BZOJ】2648: SJY摆棋子 &amp; 2716: [Violet 3]天使玩偶(kdtree)

http://www.lydsy.com/JudgeOnline/problem.php?id=2716 http://www.lydsy.com/JudgeOnline/problem.php?id=2648 双倍经验题... kdtree裸题吧.....今天学了下kdtree...感觉挺简单的.... 其实就是对几何图形进行剖分建树,而特殊在于,x和y轴轮流剖....这样可以提供很好的性质以便于查找... (一开始脑补了个treap代替kdtree.....显然我脑残了....写到一半发现这

bzoj 2648: SJY摆棋子&amp;&amp;2716: [Violet 3]天使玩偶 --kdtree

Time Limit: 20 Sec  Memory Limit: 128 MB Description 这天,SJY显得无聊.在家自己玩.在一个棋盘上,有N个黑色棋子.他每次要么放到棋盘上一个黑色棋子,要么放上一个白色棋子,如果是白色棋子,他会找出距离这个白色棋子最近的黑色棋子.此处的距离是 曼哈顿距离 即(|x1-x2|+|y1-y2|) .现在给出N<=500000个初始棋子.和M<=500000个操作.对于每个白色棋子,输出距离这个白色棋子最近的黑色棋子的距离.同一个格子可能有多个棋子

BZOJ 2716: [Violet 3]天使玩偶 [CDQ分治]

传送门 题意: 维护二维点集P,支持以下两个操作(1)插入点(x,y)(2)给定询问(x,y),求点集中离询问点最近的点距离定义为曼哈顿距离Dis(P1,P2)=|x1-x2|+|y1-y2|n,m<=500000x,y<=1000000 时间,$x$,$y$ $CDQ$分治里需要四个象限分类讨论,树状数组维护最大值 然后有两个象限是后缀和 然后跟$PoPoQQQ$学了一个神奇的技巧,树状数组加一个时间戳,就可以不用每次清空之前的操作了 #include <iostream> #i

bzoj 2716 [Violet 3]天使玩偶 【CDQ分治】

KD-tree可做,但是我不会暂时不考虑 大意:在二维平面内,给定n个点,m个操作.操作A:加入一个点:操作B:询问一个点与平面上加入的点的最近距离 不封装会T不封装会T不封装会T不封装会T不封装会T不封装会T不封装会T不封装会T不封装会T不封装会T不封装会T 把初始存在的点也看成加点操作 首先,曼哈顿距离取绝对值很烦,所以我们可以通过转坐标,把左上 右上 左下 右下通过转坐标都变成左下,最后取个min即可.于是对于(x,y)左下的点(x1,y1),dis=x-x1+y-y1=(x+y)-(x1

BZOJ2716 &amp; NKOJ2739:[Violet 3]天使玩偶——题解

同样方便非权限玩家,NKOJ有这道题. http://oi.nks.edu.cn/zh/Problem/Details/2739 http://www.lydsy.com/JudgeOnline/problem.php?id=2716 样例输入 2 31 12 32 1 21 3 32 4 2 样例输出 1 2 ———————————————————————————————— 整整一个上午的时间,终于DEBUG出来了,原来是因为我数组开小了…… 首先我们很容易想到一个三元组(t,x,y),其中t