BZOJ.2716.[Violet3]天使玩偶(CDQ分治 坐标变换)
考虑对于两个点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分治 坐标变换)的更多相关文章
- BZOJ.2716.[Violet3]天使玩偶(K-D Tree)
题目链接 KD-Tree.因为插入过多点后可能会退化成链,所以左/右子树sz > α*整棵子树sz时对整棵子树进行重构. 树的节点数必须是3n?why?洛谷,BZOJ都这样..(数据范围错了吧 ...
- [BZOJ2716] [Violet 3]天使玩偶(CDQ分治)
[BZOJ2716] [Violet 3]天使玩偶(CDQ分治) 题面 Ayu 在七年前曾经收到过一个天使玩偶,当时她把它当作时间囊埋在了地下.而七年后 的今天,Ayu 却忘了她把天使玩偶埋在了哪里, ...
- BZOJ 2716: [Violet 3]天使玩偶( CDQ分治 + 树状数组 )
先cdq分治, 然后要处理点对答案的贡献, 可以以询问点为中心分成4个区域, 然后去掉绝对值(4种情况讨论), 用BIT维护就行了. --------------------------------- ...
- [bzoj] 2716 天使玩偶 || CDQ分治
原题 已知n个点有天使玩偶,有m次操作: 操作1:想起来某个位置有一个天使玩偶 操作2:询问离当前点最近的天使玩偶的曼哈顿距离 显然的CDQ问题,三维分别为时间,x轴,y轴. 但是这道题的问题在于最近 ...
- BZOJ 2716 [Violet 3]天使玩偶 (CDQ分治、树状数组)
题目链接: https://www.lydsy.com/JudgeOnline/problem.php?id=2716 怎么KD树跑得都那么快啊..我写的CDQ分治被暴虐 做四遍CDQ分治,每次求一个 ...
- BZOJ 2716 Violet 3 天使玩偶 CDQ分治
题目大意:初始给定平面上的一个点集.提供两种操作: 1.将一个点增加点集 2.查询距离一个点最小的曼哈顿距离 K-D树是啥...不会写... 我仅仅会CDQ分治 对于一个询问,查询的点与这个点的位置关 ...
- 洛谷P4169 天使玩偶 CDQ分治
还是照着CDQ的思路来. 但是有一些改动: 要求4个方向的,但是可爱的CDQ分治只能求在自己一个角落方向上的.怎么办?旋转!做4次就好了. 统计的不是和,而是——max!理由如下: 设当前点是(x,y ...
- CH 4701 - 天使玩偶 - [CDQ分治]
题目链接:传送门 关于CDQ分治(参考李煜东<算法竞赛进阶指南>): 对于一系列操作,其中的任何一个询问操作,其结果必然等价于:初始值 + 此前所有的修改操作产生的影响. 假设共有 $m$ ...
- 天使玩偶:CDQ分治
这道好(du)题(liu)还是很不错的 挺锻炼代码能力和不断优化 卡常的能力的. 对于 每次询问 我都可以将其分出方向 然后 写 也就是针对于4个方向 左下 左上 右下 右上 这样的话 就成功转换了问 ...
随机推荐
- bzoj千题计划268:bzoj3131: [Sdoi2013]淘金
http://www.lydsy.com/JudgeOnline/problem.php?id=3131 如果已知 s[i]=j 表示有j个<=n数的数码乘积=i 那么就会有 s[a1]*s[a ...
- 一个中国地图的SVG,可以带参数
<script src="http://files.cnblogs.com/files/LoveOrHate/jquery.min.js"></script> ...
- [整理]x=x++和x=++x
最近看java面试题,再次遇到x=x++,之前一直按照C语言中对自增运算符++的解释去理解.殊不知自己犯了严重的错误. (1)不同的语言的编译器,会导致相同的代码最终执行的结果不确定; (2)而且就算 ...
- 网页中创建音频、视频和Flash等多媒体:object元素
<object>元素:它主要用于定义网页中的多媒体,比如音频.视频.Java applets.PDF.ActiveX和Flash.Object标签是成对出现的,在object标签内可以使用 ...
- Angular 下的 directive (part 2)
ngCloak ngCloak指令被使用在,阻止angular模板从浏览器加载的时候出现闪烁的时候.使用它可以避免闪烁问题的出现. 该指令可以应用于<body>元素,但首选使用多个ng ...
- [python]python错误集锦
ValueError: invalid literal : ''不能将非数字字符串转换为整型 object has no attribute 对象调用一个没有的方法(内建或自定义) TypeError ...
- 两个不能同时共存的条件orWhere查询
举例: //我的所有的积分记录 1,我分享的:2,我点击的:(两个条件不能共存) $activity_log = ActivitySharedLog::where(function ($query) ...
- [转]Linux联网问题
一.Kali联网问题 首先ifconfig,可以看到没有正在工作的网卡,只有localhost 然后ifconfig -a,可以看到eth0这块网卡并没有离家出走,只是罢工了而已 打开/etc/net ...
- MySQL常见的两种存储引擎:MyISAM与InnoDB的爱恨情仇
Java面试通关手册(Java学习指南,欢迎Star,会一直完善下去,欢迎建议和指导):https://github.com/Snailclimb/Java_Guide 一 MyISAM 1.1 My ...
- springboot整合rabbirmq(3.7.9)中使用mandatory参数获取匹配失败的消息以及存入rabbitmq备份交换器中!
先说下这个参数的作用: /** * Mandatory为true时,消息通过交换器无法匹配到队列会返回给生产者 * 为false时,匹配不到会直接被丢弃 */在一些特定场景下还是有用处的!接下来说一下 ...