[Luogu4169][Violet]天使玩偶/SJY摆棋子

luogu

题意

一个平面上有\(n\)个点,\(m\)次操作,每次新增一个点,或者是询问离某个点最近的点的距离。这里的距离是曼哈顿距离。
\(n,m\le3*10^5\)

sol

写一发\(CDQ\)。
只考虑询问点在其他点的右上方的情况,假设询问点是\(A\),那么所求的距离就是\((X_A-X_i)+(Y_A-Y_i)=(X_A+Y_A)-(X_i+Y_i)\)。
所以我们只需要找出满足\(X_i \le X_A,Y_i \le Y_A\)中\(X_i+Y_i\)的最大值就好了。
\(CDQ\)前先按时间戳排序,向上归并时按\(X\)排序。考虑左边对右边的贡献时,按\(Y\)值为下标插入树状数组,然后查询前缀最大值。
对于不在右上方的情况,只要把坐标轴翻转四次就可以了。

然而。
这题卡常。
以下是一些卡常技巧。

清空树状数组的时候,如果当前位已经是\(0\)就直接\(return\)。
预先记录按照时间戳的排序,每次\(CDQ\)完后直接复制一遍,不需要排序。
删除不必要的点(不会被任何询问考虑到的点)

常数巨大无比。

code

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int gi()
{
    int x=0,w=1;char ch=getchar();
    while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
    if (ch=='-') w=0,ch=getchar();
    while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    return w?x:-x;
}
const int N = 1e6+5;
struct node{
    int tim,opt,x,y;
    bool operator < (const node &b) const
        {
            if (x!=b.x) return x<b.x;
            if (y!=b.y) return y<b.y;
            return opt<b.opt;
        }
}a[N],p[N],q[N];
int n,m,X,Y,c[N],ans[N];
inline void modify(int k,int v){while(k<=Y)c[k]=max(c[k],v),k+=k&-k;}
inline int query(int k){int s=0;while(k)s=max(s,c[k]),k-=k&-k;return s;}
inline void clear(int k){while(k<=Y)if(c[k])c[k]=0,k+=k&-k;else return;}
void CDQ(int l,int r)
{
    if (l==r) return;
    int mid=l+r>>1;CDQ(l,mid);CDQ(mid+1,r);
    int L=l,R=mid+1;
    for (int i=l;i<=r;++i)
        if (L<=mid&&(R>r||p[L]<p[R]))
        {
            q[i]=p[L++];
            if (q[i].opt==1) modify(q[i].y,q[i].x+q[i].y);
        }
        else
        {
            q[i]=p[R++];
            if (q[i].opt==2)
            {
                int tmp=query(q[i].y);
                if (tmp) ans[q[i].tim]=min(ans[q[i].tim],q[i].x+q[i].y-tmp);
            }
        }
    for (int i=l;i<=r;++i) p[i]=q[i],clear(p[i].y);
}
void Delete()
{
    int xx=0,yy=0;m=0;
    for (int i=1;i<=n;++i)
        if (p[i].opt==2)
            xx=max(xx,p[i].x),yy=max(yy,p[i].y);
    for (int i=1;i<=n;++i)
        if (p[i].x<=xx&&p[i].y<=yy)
            q[++m]=p[i];
    for (int i=1;i<=m;++i) p[i]=q[i];
}
int main()
{
    n=gi();m=gi();memset(ans,63,sizeof(ans));
    for (int i=1;i<=n;++i)
    {
        a[i]=(node){0,1,gi()+1,gi()+1};
        X=max(X,a[i].x);Y=max(Y,a[i].y);
    }
    for (int i=1;i<=m;++i)
    {
        a[++n]=(node){i,gi(),gi()+1,gi()+1};
        X=max(X,a[n].x);Y=max(Y,a[n].y);
    }
    ++X;++Y;
    for (int i=1;i<=n;++i) p[i]=a[i];
    Delete();CDQ(1,m);
    for (int i=1;i<=n;++i) p[i]=a[i],p[i].x=X-p[i].x;
    Delete();CDQ(1,m);
    for (int i=1;i<=n;++i) p[i]=a[i],p[i].y=Y-p[i].y;
    Delete();CDQ(1,m);
    for (int i=1;i<=n;++i) p[i]=a[i],p[i].x=X-p[i].x,p[i].y=Y-p[i].y;
    Delete();CDQ(1,m);
    for (int i=1;i<=n;++i) if (a[i].opt==2) printf("%d\n",ans[a[i].tim]);
    return 0;
}

原文地址:https://www.cnblogs.com/zhoushuyu/p/8809015.html

时间: 2024-10-09 15:06:35

[Luogu4169][Violet]天使玩偶/SJY摆棋子的相关文章

[Violet]天使玩偶/SJY摆棋子

Luogu4169 每次操作加入平面上一个点 , 或者询问离一个点最近的点的距离 CDQ分治模板 \(1.\)solve(l,mid); \(2.\)solve(mid+1,r); \(3.\)计算\([l,mid]\)中修改操作对\([mid+1,r]\)中查询操作的影响 /* ---------------------- [CDQ分治] 天使玩偶 1.solve(l,mid); 2.solve(mid+1,r); 3.计算[l,mid]中修改操作对[mid+1,r]中查询操作的影响 ----

Luogu P4169 [Violet]天使玩偶/SJY摆棋子

传送门 二维平面修改+查询,cdq分治可以解决. 求关于某个点曼哈顿距离(x,y坐标)最近的点——dis(A,B) = |Ax-Bx|+|Ay-By| 但是如何去掉绝对值呢? 查看题解发现假设所有的点都在查询点的左下方,dis(A,B) = (Ax-Bx)+(Ay-By) = (Ax+Ay)-(Bx+By) 只要求满足Bx<Ax,By<Ay且Bx,By之和最大的点就好了. 那么如何把所有的点转化到该查询的左下呢? 对于每个查询,可以把一.二.四象限的点都通过对称转移到第三象限.但查询很多,不可

P4169 [Violet]天使玩偶/SJY摆棋子

1 // luogu-judger-enable-o2 2 #include<cstdio> 3 #include<iostream> 4 using namespace std; 5 const int maxn=1e7+10; 6 const int inf=2e7+7; 7 struct node 8 { 9 int x,y,id,ans,time; 10 }a[maxn],b[maxn],tt[maxn];; 11 int flag; 12 int len,x,y; 13

【bzoj2648&amp;bzoj2716】[Violet3]天使玩偶&amp;SJY摆棋子【kd树】

1BK捌脊允4iyo松纲06http://weibo.com/u/6264971116 382u60L86vl戎导屯http://www.docin.com/nqra496 u23j6h0敢d缴遮ahttp://www.facebolw.com/space/2104191 86褐2咕6镜y米0uhttp://huiyi.docin.com/sina_6352810924 160hA坷Yk闭苫6尾ehttp://shequ.docin.com/sina_6267166088 侍4E0pf范星17南

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-2648&amp;2716】SJY摆棋子&amp;天使玩偶 KD Tree

2648: SJY摆棋子 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 2459  Solved: 834[Submit][Status][Discuss] Description 这天,SJY显得无聊.在家自己玩.在一个棋盘上,有N个黑色棋子.他每次要么放到棋盘上一个黑色棋子,要么放上一个白色棋子,如果是白色棋子,他会找出距离这个白色棋子最近的黑色棋子.此处的距离是 曼哈顿距离 即(|x1-x2|+|y1-y2|) .现在给出N<=500000

BZOJ 2648(SJY摆棋子-KD_Tree)

2648: SJY摆棋子 Time Limit: 20 Sec  Memory Limit: 128 MB Submit: 1180  Solved: 391 [Submit][Status][Discuss] Description 这天,SJY显得无聊.在家自己玩.在一个棋盘上,有N个黑色棋子.他每次要么放到棋盘上一个黑色棋子,要么放上一个白色棋子,如果是白色棋子,他会找出距离这个白色棋子最近的黑色棋子.此处的距离是 曼哈顿距离 即(|x1-x2|+|y1-y2|) .现在给出N<=5000

【BZOJ2648】SJY摆棋子 [KD-tree]

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

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

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