题目链接

考虑对于两个点a,b,距离为|x[a]-x[b]|+|y[a]-y[b]|,如果a在b的右上,那我们可以把绝对值去掉,即x[a]+y[a]-(x[b]+y[b])。

即我们要求满足x[b]<=x[a]且y[b]<=y[a]的最大的x[b]+y[b],用CDQ分治+树状数组解决。

那如果a不在b的右上呢?可以通过坐标变换解决(因为要求的只是相对距离)。

坐标变换可以用Xmax或Ymax减去xi或yi。

如果还用之前的方法,每次变换坐标前都要把操作序列变为初始序列(时间有序),但是这样很慢。。

不如在每次分治前按x sort一遍,分治中再以tm为关键字排序(同一区间内要时间有序)

优化: 遇到修改时才修改。所以先排好序再扫一遍更新答案

//43796kb	32744ms
#include <cstdio>
#include <cctype>
#include <algorithm>
//#define gc() getchar()
#define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++)
#define lb(x) (x)&-(x)
const int N=5e5+5,MAXIN=2e6; int n,m,qcnt,acnt,Ans[N],A[N<<1];
char IN[MAXIN],*SS=IN,*TT=IN;
struct Operation
{
int type,x,y,tm;
Operation() {}
Operation(int t,int _x,int _y,int _tm): type(t),x(_x),y(_y),tm(_tm) {}
bool operator <(const Operation &a)const{
return x==a.x?tm<a.tm:x<a.x;
}
}q[N<<1],tmp[N<<1]; namespace BIT
{
int Max,t[1000005];
void Update(int p,int v){
while(p<=Max) t[p]=std::max(t[p],v),p+=lb(p);
}
int Query(int p){
int res=0;
while(p) res=std::max(t[p],res),p^=lb(p);//^代替-
return res;
}
void Clear(int p){
while(p<=Max)//被这个Max坑半晚上。。
if(t[p]) t[p]=0,p+=lb(p);
else break;
}
}
inline int read()
{
int now=0;register char c=gc();
for(;!isdigit(c);c=gc());
for(;isdigit(c);now=now*10+c-'0',c=gc());
return now;
}
void CDQ(int l,int r)
{
if(l<r)
{
int m=l+r>>1;
int p1=l,p2=m+1,t=0,val;
for(int i=l; i<=r; ++i)
if(q[i].tm<=m) tmp[p1++]=q[i];
else tmp[p2++]=q[i];
for(int i=l; i<=r; ++i) q[i]=tmp[i];//先排好 这样之后就可以只在查询时更新了(不需要排序了)
p1=l, p2=m+1;
for(; p2<=r; ++p2)
if(q[p2].type)
{
for(; p1<=m&&q[p1].x<=q[p2].x; ++p1)
if(!q[p1].type) A[++t]=q[p1].y,BIT::Update(q[p1].y,q[p1].x+q[p1].y);
if(val=BIT::Query(q[p2].y))
Ans[q[p2].type]=std::min(Ans[q[p2].type],q[p2].x+q[p2].y-val);//只在有点时更新答案! 否则答案会是它的x+y
}
// for(int i=l; i<p1; ++i)
// if(!q[i].type) BIT::Clear(q[i].y);
for(int i=1; i<=t; ++i) BIT::Clear(A[i]);
CDQ(l,m), CDQ(m+1,r);
}
} int main()
{
n=read(),m=read();
int Xmax=0,Ymax=0;
for(int x,y,i=1; i<=n; ++i)//非负坐标...
x=read()+1,y=read()+1,Xmax=std::max(Xmax,x),Ymax=std::max(Ymax,y),
q[++qcnt]=Operation(0,x,y,qcnt);
for(int t,x,y,i=1; i<=m; ++i)
t=read(),x=read()+1,y=read()+1,Xmax=std::max(Xmax,x),Ymax=std::max(Ymax,y),
q[++qcnt]=Operation(t==1?0:++acnt,x,y,qcnt);
++Xmax,++Ymax,BIT::Max=Ymax;
for(int i=1; i<=acnt; ++i) Ans[i]=Xmax+Ymax; std::sort(q+1,q+1+qcnt), CDQ(1,qcnt); for(int i=1; i<=qcnt; ++i) q[i].x=Xmax-q[i].x;
std::sort(q+1,q+1+qcnt), CDQ(1,qcnt); for(int i=1; i<=qcnt; ++i) q[i].y=Ymax-q[i].y;
std::sort(q+1,q+1+qcnt), CDQ(1,qcnt); for(int i=1; i<=qcnt; ++i) q[i].x=Xmax-q[i].x;
std::sort(q+1,q+1+qcnt), CDQ(1,qcnt); for(int i=1; i<=acnt; ++i) printf("%d\n",Ans[i]); return 0;
}

最初的代码(肯定是会T):

//懒得改了 看另一个吧。。
#include <cstdio>
#include <cctype>
#include <algorithm>
#define gc() getchar()
#define lb(x) (x)&-(x)
const int N=3e5+5; int n,m,qcnt,acnt,Ans[N];
struct Operation
{
int type,x,y;
Operation() {};
Operation(int t,int _x,int _y): type(t),x(_x),y(_y) {};
bool operator <(const Operation &a)const{
return x==a.x?type<a.type:x<a.x;
}
}q[N<<1],tmp[N<<1],A[N<<1]; namespace BIT
{
int Max,t[1000005];
void Update(int p,int v){
while(p<=Max) t[p]=std::max(t[p],v),p+=lb(p);
}
int Query(int p){
int res=0;
while(p) res=std::max(t[p],res),p-=lb(p);
return res;
}
void Clear(int p){
while(p<=Max)//被这个Max坑了半晚上。。
if(t[p]) t[p]=0,p+=lb(p);
else break;
}
}
inline int read()
{
int now=0;register char c=gc();
for(;!isdigit(c);c=gc());
for(;isdigit(c);now=now*10+c-'0',c=gc());
return now;
}
void CDQ(int l,int r)
{//同理可以只在后半部分修改时更新前半部分 这个tm是有序的 结束后要按x归并使x有序
if(l<r)
{
int m=l+r>>1; CDQ(l,m), CDQ(m+1,r);
int p1=l,p2=m+1,t=0,val;
while(p1<=m&&p2<=r)
{
if(q[p1]<q[p2])
{
if(!q[p1].type) BIT::Update(q[p1].y,q[p1].x+q[p1].y);
tmp[t++]=q[p1++];
}
else
{
if(q[p2].type)
if(val=BIT::Query(q[p2].y))//只在有点时更新答案! 否则答案会是它的x+y
Ans[q[p2].type]=std::min(Ans[q[p2].type],q[p2].x+q[p2].y-val);
tmp[t++]=q[p2++];
}
}
if(p1<=m)
{
for(int i=l; i<p1; ++i)
if(!q[i].type) BIT::Clear(q[i].y);
while(p1<=m) tmp[t++]=q[p1++];
}
else
{
while(p2<=r)
{
if(q[p2].type)
if(val=BIT::Query(q[p2].y))
Ans[q[p2].type]=std::min(Ans[q[p2].type],q[p2].x+q[p2].y-val);
tmp[t++]=q[p2++];
}
for(int i=l; i<=m; ++i)
if(!q[i].type) BIT::Clear(q[i].y);
}
for(int i=0; i<t; ++i) q[l+i]=tmp[i];
}
} int main()
{
n=read(),m=read();
int Xmax=0,Ymax=0;
for(int x,y,i=1; i<=n; ++i)//非负坐标...
x=read()+1,y=read()+1,Xmax=std::max(Xmax,x),Ymax=std::max(Ymax,y),
q[++qcnt]=Operation(0,x,y);
for(int t,x,y,i=1; i<=m; ++i)
t=read(),x=read()+1,y=read()+1,Xmax=std::max(Xmax,x),Ymax=std::max(Ymax,y),
q[++qcnt]=Operation(t==1?0:++acnt,x,y);
++Xmax,++Ymax,BIT::Max=Ymax;
for(int i=1; i<=acnt; ++i) Ans[i]=Xmax+Ymax;
for(int i=1; i<=qcnt; ++i) A[i]=q[i]; CDQ(1,qcnt); for(int i=1; i<=qcnt; ++i) q[i]=A[i];
for(int i=1; i<=qcnt; ++i) q[i].x=Xmax-q[i].x;
CDQ(1,qcnt); for(int i=1; i<=qcnt; ++i) q[i]=A[i];
for(int i=1; i<=qcnt; ++i) q[i].y=Ymax-q[i].y;
CDQ(1,qcnt); for(int i=1; i<=qcnt; ++i) q[i]=A[i];
for(int i=1; i<=qcnt; ++i) q[i].x=Xmax-q[i].x,q[i].y=Ymax-q[i].y;
CDQ(1,qcnt); for(int i=1; i<=acnt; ++i) printf("%d\n",Ans[i]); return 0;
}

BZOJ.2716.[Violet3]天使玩偶(CDQ分治 坐标变换)的更多相关文章

  1. BZOJ.2716.[Violet3]天使玩偶(K-D Tree)

    题目链接 KD-Tree.因为插入过多点后可能会退化成链,所以左/右子树sz > α*整棵子树sz时对整棵子树进行重构. 树的节点数必须是3n?why?洛谷,BZOJ都这样..(数据范围错了吧 ...

  2. [BZOJ2716] [Violet 3]天使玩偶(CDQ分治)

    [BZOJ2716] [Violet 3]天使玩偶(CDQ分治) 题面 Ayu 在七年前曾经收到过一个天使玩偶,当时她把它当作时间囊埋在了地下.而七年后 的今天,Ayu 却忘了她把天使玩偶埋在了哪里, ...

  3. BZOJ 2716: [Violet 3]天使玩偶( CDQ分治 + 树状数组 )

    先cdq分治, 然后要处理点对答案的贡献, 可以以询问点为中心分成4个区域, 然后去掉绝对值(4种情况讨论), 用BIT维护就行了. --------------------------------- ...

  4. [bzoj] 2716 天使玩偶 || CDQ分治

    原题 已知n个点有天使玩偶,有m次操作: 操作1:想起来某个位置有一个天使玩偶 操作2:询问离当前点最近的天使玩偶的曼哈顿距离 显然的CDQ问题,三维分别为时间,x轴,y轴. 但是这道题的问题在于最近 ...

  5. BZOJ 2716 [Violet 3]天使玩偶 (CDQ分治、树状数组)

    题目链接: https://www.lydsy.com/JudgeOnline/problem.php?id=2716 怎么KD树跑得都那么快啊..我写的CDQ分治被暴虐 做四遍CDQ分治,每次求一个 ...

  6. BZOJ 2716 Violet 3 天使玩偶 CDQ分治

    题目大意:初始给定平面上的一个点集.提供两种操作: 1.将一个点增加点集 2.查询距离一个点最小的曼哈顿距离 K-D树是啥...不会写... 我仅仅会CDQ分治 对于一个询问,查询的点与这个点的位置关 ...

  7. 洛谷P4169 天使玩偶 CDQ分治

    还是照着CDQ的思路来. 但是有一些改动: 要求4个方向的,但是可爱的CDQ分治只能求在自己一个角落方向上的.怎么办?旋转!做4次就好了. 统计的不是和,而是——max!理由如下: 设当前点是(x,y ...

  8. CH 4701 - 天使玩偶 - [CDQ分治]

    题目链接:传送门 关于CDQ分治(参考李煜东<算法竞赛进阶指南>): 对于一系列操作,其中的任何一个询问操作,其结果必然等价于:初始值 + 此前所有的修改操作产生的影响. 假设共有 $m$ ...

  9. 天使玩偶:CDQ分治

    这道好(du)题(liu)还是很不错的 挺锻炼代码能力和不断优化 卡常的能力的. 对于 每次询问 我都可以将其分出方向 然后 写 也就是针对于4个方向 左下 左上 右下 右上 这样的话 就成功转换了问 ...

随机推荐

  1. SQL语句(十一)函数查询

    (十一)函数查询 1. 聚合函数 对一组值进行计算,得到一个返回值 SUM(), 求和 AVG(), 求平均 MIN(), 求最小 MAX(), 求最大 COUNT(), 计数,即个数 --例1 求所 ...

  2. info replication

    主Redis设置值:redis-cli -h 192.168.18.121 -p 63800 -a tinywan123456 登陆从1:redis-cli -h 192.168.18.121 -p ...

  3. Javascript Image Slider 插件注册机

    Javascript Image Slider 是个不错的轮播插件,兼容 IE 7.0+, Firefox 1.5+, Chrome 1.0+, Safari 3+, Opera 9.0+, Nets ...

  4. javascript鼠标拖拽的那些事情

    <html> <head> <title>javascript鼠标拖拽的那些事情</title> <meta http-equiv="C ...

  5. [整理]Win下好用的Markdown工具

    用过haroopad,MarkPad,Sublime + markdown插件,前2款勉强能用,都处于继续开发中,haroopad支持的语法相对较少,提示也不明显,MarkPad还是有不少bug. 后 ...

  6. 【问题收集·中级】关于XMPP使用Base传送图片

    [问题收集·中级]关于XMPP使用Base传送图片 下面是我与博友的问答过程:并在最后链接附录了相应的文件: 博友问题:  16:35:38 他跟我说要 内容图片  base64编码 上传..博友问题 ...

  7. iOS 在viewDidLayoutSubviews自动布局crash问题

    1 viewDidLayoutSubviews改成viewWillLayoutSubviews在iOS7上就不会crash了2 viewDidLoad中还需要设置self.edgesForExtend ...

  8. HTML5+CSS把footer固定在底部

    在刚开始给网页写footer的时候,我们会碰到一个让人烦躁的问题:当页面内容太少时,footer显示在了页面中间,这是我们不希望出现的,我们希望它能够永远呆在底部,不管网页的内容是多还是少.下面的代码 ...

  9. 对git简单的认识

    了解git工作区.暂存区.版本库: 其中,使用 git add .就是将文件添加到了暂存区:而git commit -m ‘desc’:将暂存区的文件添加到版本库: 每次更新项目的步骤: 1)每次更新 ...

  10. 2017/05/23 java 基础 随笔

    1.多态的好处: a.提高了代码的维护性(继承保证) b.提高了代码的扩展性(由多态保证) package com.huawei; public class Demo2 { public static ...