题目链接

考虑对于两个点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. bzoj千题计划284:bzoj2882: 工艺

    http://www.lydsy.com/JudgeOnline/problem.php?id=2882 将串S复制一遍变成SS 对SS构建后缀自动机,在上面走标号最小的边len(S)步,即可得最小循 ...

  2. J2EE架构

    从整体上讲,J2EE是使用Java技术开发企业级应用的一种事实上的工业标准(Sun公司出于其自身利益的考虑,至今没有将Java及其相关技术纳入标准化组织的体系),它是Java技术不断适应和促进企业级应 ...

  3. 20155212 2016-2017-2 《Java程序设计》第8周学习总结

    20155212 2016-2017-2 <Java程序设计>第8周学习总结 教材学习内容总结 Chapter14 1. Channel架构与操作 想要取得Channel的实作对象,可以使 ...

  4. unbind()清除指定元素绑定效果

    定义和用法 unbind() 方法移除被选元素的事件处理程序. 该方法能够移除所有的或被选的事件处理程序,或者当事件发生时终止指定函数的运行. ubind() 适用于任何通过 jQuery 附加的事件 ...

  5. 线性筛的同时得到欧拉函数 (KuangBin板子)

    线性筛的思想:每个被筛的数是通过它最小的质因子所筛去的. 这种思想保证了每个数只会被筛一次,从而达到线性.并且,这个思想实现起来非常巧妙(见代码注释)! 因为线性筛的操作中用到了倍数的关系去实现,因此 ...

  6. 洛谷 P1603 斯诺登的密码

    我一开始还没看懂非正规数字的意义,以为那里写的单词不算,蒙了好久,而且这题非常考验仔细程度,一不小心就RE,WA. 嗯,好像讲了些废话,那我们看看思路,我的做法和前面的大佬们有些不同,因为这题只有六个 ...

  7. deeplearning.ai学习seq2seq模型

    一.seq2seq架构图 seq2seq模型左边绿色的部分我们称之为encoder,左边的循环输入最终生成一个固定向量作为右侧的输入,右边紫色的部分我们称之为decoder.单看右侧这个结构跟我们之前 ...

  8. Hibernate常用的Java数据类型映射到mysql和Oracle

    研究了常用的Java基本数据类型在mysql和oracle数据库的映射类型.这里使用的是包装类型做研究,一般在hibernate声明的时候最好不要用基本类型,因为数据库中的null空数据有可能映射为基 ...

  9. Servlet笔记9--Cookie

    Cookie: 使用Cookie机制实现十天内免登陆: Servlet程序: package com.bjpowernode.javaweb.servlet; import java.io.IOExc ...

  10. inux系统用户名和全名有什么区别

    问:linux系统安装完毕,进入系统,创建用户的时候,要填入用户名和全名,请问用户名和全名有什么区别,登录的时候,是用户名还是全名? ================================= ...