[BZOJ2716] [Violet 3]天使玩偶(CDQ分治)
[BZOJ2716] [Violet 3]天使玩偶(CDQ分治)
题面
Ayu 在七年前曾经收到过一个天使玩偶,当时她把它当作时间囊埋在了地下。而七年后 的今天,Ayu 却忘了她把天使玩偶埋在了哪里,所以她决定仅凭一点模糊的记忆来寻找它。
我们把 Ayu 生活的小镇看作一个二维平面坐标系,而 Ayu 会不定时地记起可能在某个点 (xmy) 埋下了天使玩偶;或者 Ayu 会询问你,假如她在 (x,y) ,那么她离近的天使玩偶可能埋下的地方有多远。
因为 Ayu 只会沿着平行坐标轴的方向来行动,所以在这个问题里我们定义两个点之间的距离为dist(A,B)=|Ax-Bx|+|Ay-By|。其中 Ax 表示点 A的横坐标,其余类似。
分析
由于距离为曼哈顿距离,绝对值符号不好处理,我们考虑分类讨论。
假如答案在询问点A的左下方,那么距离为\(x_A-x_B+y_A-y_B=(x_A+y_A)-(x_B+y_B)\)
由于\(x_A+y_A\)为定值,我们要距离最小,只要在询问点A的左下方求一个\((x_B+y_B)\)最小的点即可。这是一个经典的cdq分治问题,这是一个经典的三维偏序问题,详情可参考[BZOJ 2683] 简单题 (CDQ分治)
其他情况怎么办呢?其实我们可以通过翻折点来避免分类讨论。假如所有点里最小的y坐标为ymin,我们把点以直线y=ymin对称,这样原来在A上方的点变成了原来在A下方的点,可以用上面的方法来处理。x坐标同理。因此我们只要改变坐标,然后跑CDQ分治即可。一共要跑4次CDQ分治(四倍的快乐?)
常数较大,注意卡常
代码
//分类讨论上下左右四种情况
//通过翻转坐标全部变成左下的情况
//min(x-x'+y-y')=x+y-max(x'+y')
//转化成三维偏序查最大值: x,y,时间都小的最大值
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxn 2000000
#define INF 0x3f3f3f3f
#define register
using namespace std;
inline void qread(int &x){
x=0;
int sign=1;
char c=getchar();
while(c<'0'||c>'9'){
if(c=='-') sign=-1;
c=getchar();
}
while(c>='0'&&c<='9'){
x=x*10+c-'0';
c=getchar();
}
x=x*sign;
}
inline void qprint(int x){
if(x<0){
putchar('-');
qprint(-x);
}else if(x==0){
putchar('0');
return;
}else{
if(x>=10) qprint(x/10);
putchar(x%10+'0');
}
}
int n,m,cnt,qcnt;
struct node{
int a;
int b;
int c;
int type;
int id;
int ans;
node(){
}
node(int _a,int _b,int _c,int _type){
a=_a;
b=_b;
c=_c;
type=_type;
id=0;
ans=-INF;
}
node(int _a,int _b,int _c,int _type,int _id){
a=_a;
b=_b;
c=_c;
type=_type;
id=_id;
ans=-INF;
}
};
node q[maxn+5],dat[maxn+5];//dat保存翻转前的变量
int cmpa(node p,node q){
if(p.a==q.a){
if(p.b==q.b) return p.c<q.c;
else return p.b<q.b;
}else return p.a<q.a;
}
int cmpb(node p,node q){
if(p.b==q.b) return p.c<q.c;
else return p.b<q.b;
}
struct fenwick_tree{//树状数组可以维护前缀最大值,且常数小
int c[maxn+5];
inline int lowbit(int x){
return x&(-x);
}
inline void update(int pos,int val){
for(int i=pos;i<=cnt;i+=lowbit(i)) c[i]=max(c[i],val);
}
inline void clear(int pos){
for(int i=pos;i<=cnt;i+=lowbit(i)) c[i]=-INF;
}
inline int query(int pos){
int ans=-INF;
for( int i=pos;i>0;i-=lowbit(i)) ans=max(ans,c[i]);
return ans;
}
}T;
node tmp[maxn+5];
void cdq_divide(int l,int r){
if(l==r) return;
int mid=(l+r)>>1;
cdq_divide(l,mid);
cdq_divide(mid+1,r);
int ptr=l-1;
for(int i=mid+1;i<=r;i++){
if(q[i].type==2){//这样写有玄学优化作用,原因未知.
while(ptr<mid&&q[ptr+1].b<=q[i].b){
ptr++;
if(q[ptr].type==1) T.update(q[ptr].c,q[ptr].a+q[ptr].b);
}
q[i].ans=max(q[i].ans,T.query(q[i].c));
}
}
for(int i=l;i<=ptr;i++) if(q[i].type==1) T.clear(q[i].c);
int num=l-1;
int pl=l,pr=mid+1;
while(pl<=mid&&pr<=r){
if(cmpb(q[pl],q[pr])) tmp[++num]=q[pl++];
else tmp[++num]=q[pr++];
}
while(pl<=mid) tmp[++num]=q[pl++];
while(pr<=r) tmp[++num]=q[pr++];
for(int i=l;i<=r;i++) q[i]=tmp[i];
}
int res[maxn+5];
int main(){
int t,x,y;
int maxx,maxy,minx,miny;
maxx=maxy=-INF;
minx=miny=INF;
qread(n);
qread(m);
for(int i=1;i<=n;i++){
qread(x);
qread(y);
cnt++;
q[cnt]=node(x,y,cnt,1);
maxx=max(maxx,x);
minx=min(minx,x);
maxy=max(maxy,y);
miny=min(miny,y);
}
for(int i=1;i<=m;i++){
qread(t);
qread(x);
qread(y);
if(t==1){
cnt++;
q[cnt]=node(x,y,cnt,1);
}else{
cnt++;
qcnt++;
q[cnt]=node(x,y,cnt,2,qcnt);
}
maxx=max(maxx,x);
minx=min(minx,x);
maxy=max(maxy,y);
miny=min(miny,y);
}
for(int i=1;i<=cnt;i++) dat[i]=q[i];
for(int i=1;i<=qcnt;i++) res[i]=INF;
for(int i=1;i<=cnt;i++) T.c[i]=-INF;
sort(q+1,q+1+cnt,cmpa);//左下
cdq_divide(1,cnt);
for(int i=1;i<=cnt;i++){
if(q[i].type==2) res[q[i].id]=min(res[q[i].id],q[i].a+q[i].b-q[i].ans);
}
for(int i=1;i<=cnt;i++){//右下
q[i]=dat[i];
q[i].a=2*maxx-q[i].a;
}
sort(q+1,q+1+cnt,cmpa);
cdq_divide(1,cnt);
for(int i=1;i<=cnt;i++){
if(q[i].type==2) res[q[i].id]=min(res[q[i].id],q[i].a+q[i].b-q[i].ans);
}
for(int i=1;i<=cnt;i++){//左上
q[i]=dat[i];
q[i].b=2*maxy-q[i].b;
}
sort(q+1,q+1+cnt,cmpa);
cdq_divide(1,cnt);
for(int i=1;i<=cnt;i++){
if(q[i].type==2) res[q[i].id]=min(res[q[i].id],q[i].a+q[i].b-q[i].ans);
}
for(int i=1;i<=cnt;i++){//右上
q[i]=dat[i];
q[i].a=2*maxx-q[i].a;
q[i].b=2*miny-q[i].b;
}
sort(q+1,q+1+cnt,cmpa);
cdq_divide(1,cnt);
for(int i=1;i<=cnt;i++){
if(q[i].type==2) res[q[i].id]=min(res[q[i].id],q[i].a+q[i].b-q[i].ans);
}
for(int i=1;i<=qcnt;i++){
qprint(res[i]);
putchar('\n');
}
}
[BZOJ2716] [Violet 3]天使玩偶(CDQ分治)的更多相关文章
- BZOJ 2716: [Violet 3]天使玩偶( CDQ分治 + 树状数组 )
先cdq分治, 然后要处理点对答案的贡献, 可以以询问点为中心分成4个区域, 然后去掉绝对值(4种情况讨论), 用BIT维护就行了. --------------------------------- ...
- BZOJ 2716 Violet 3 天使玩偶 CDQ分治
题目大意:初始给定平面上的一个点集.提供两种操作: 1.将一个点增加点集 2.查询距离一个点最小的曼哈顿距离 K-D树是啥...不会写... 我仅仅会CDQ分治 对于一个询问,查询的点与这个点的位置关 ...
- BZOJ 2716 [Violet 3]天使玩偶 (CDQ分治、树状数组)
题目链接: https://www.lydsy.com/JudgeOnline/problem.php?id=2716 怎么KD树跑得都那么快啊..我写的CDQ分治被暴虐 做四遍CDQ分治,每次求一个 ...
- bzoj2648SJY摆棋子&&bzoj2716[Violet 3]天使玩偶*
bzoj2648SJY摆棋子 bzoj2716[Violet 3]天使玩偶 题意: 棋盘上有n个棋子,现在有m个操作,一种是加棋子,一种是查询离某个点最近的棋子.n,m≤500000. 题解: 先将已 ...
- BZOJ2716 [Violet 3]天使玩偶 【CDQ分治】
题目 输入格式 输出格式 输入样例 //样例太长就不贴了.... 输出样例 //见原题 提示 题解 我们将曼哈顿距离式子中的绝对值去掉,每次只考虑x,y比当前点小的更新答案. 为了使所有点都对答案进行 ...
- [bzoj] 2716 天使玩偶 || CDQ分治
原题 已知n个点有天使玩偶,有m次操作: 操作1:想起来某个位置有一个天使玩偶 操作2:询问离当前点最近的天使玩偶的曼哈顿距离 显然的CDQ问题,三维分别为时间,x轴,y轴. 但是这道题的问题在于最近 ...
- bzoj2716: [Violet 3]天使玩偶
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> #i ...
- 洛谷P4169 天使玩偶 CDQ分治
还是照着CDQ的思路来. 但是有一些改动: 要求4个方向的,但是可爱的CDQ分治只能求在自己一个角落方向上的.怎么办?旋转!做4次就好了. 统计的不是和,而是——max!理由如下: 设当前点是(x,y ...
- CH 4701 - 天使玩偶 - [CDQ分治]
题目链接:传送门 关于CDQ分治(参考李煜东<算法竞赛进阶指南>): 对于一系列操作,其中的任何一个询问操作,其结果必然等价于:初始值 + 此前所有的修改操作产生的影响. 假设共有 $m$ ...
随机推荐
- 搭建DHCP服务实现动态分配IP地址-NTP网络时间同步
本节所讲内容: DHCP服务器工作原理 使用DHCP为局域网中的机器分配IP地址 使用DHCP为服务器分配固定IP地址 ntpdate加计划任务同步服务器时间 实验环境: 服务端:xuegod63 ...
- Java内存模型(JMM)的可见性
JMM(Java Memory Model)内存模型之可见性 JMM是Java内存模型的缩写,本身是一种抽象的概念,并不真实存在,它描述的是一组规则或规范,通过这组规范定义了程序中各个变量(包括实例字 ...
- SpringBoot整合表单验证注解@Validated,以及分组验证
首先引入jar包 <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate ...
- 包、time、datetime、hashlib和hmac、request、re
目录 包 包的特点 time模块 datetime模块 hashlib模块和hmac模块 hmac密钥(加盐) typing模块 request模块 正则模块 以下必须得记住 哪些做了解 包 包,这里 ...
- CF1244C
题目描述 给出n,p,w,d,求(x,y,z)使得 xw+yd=p x+y+z=n 其中d<w<10^5^ 题解 显然扩欧啊( 来自天国的long long y如果大于等于w,则显然可以把 ...
- POJ 3181 Dollar Dayz ( 完全背包 && 大数高精度 )
题意 : 给出目标金额 N ,问你用面额 1~K 拼成 N 的方案有多少种 分析 : 完全背包的裸题,完全背包在 DP 的过程中实际就是列举不同的装填方案数来获取最值的 故状态转移方程为 dp[i] ...
- Java——容器(Auto-boxing/unboxing)
[打包/解包] 在Map中需要增加一个数值时,需要new一个对象出来,输出后又得进行强制类型转换,这就造成不便.在JDK1.5中使用Map接口提供了一种新的机制. 在合适的时机自动打包/解包(在J ...
- 回声状态网络ESN(Echo State Networks)
1.1 网络结构 ESN通过随机地部署大规模系数链接的神经元构成网络隐层,一般称为"储备池".ESN网络具有的特点如下: (1)包含数目相对较多的神经元: (2)神经元之间的连接关 ...
- git 部署服务
git 知识 服务器知识 1.在本地完成代码的编写, 然后通过 git 管理版本. 在编码完成后 git push 到 git 云端(github 或者 码云 及其他). 2.在服务器端安装 git ...
- AT2370 Piling Up
https://www.luogu.org/jump/atcoder/2370 题解 答案不是\(2^{2m}\)因为每轮的第一次取球可能会不够. 我们可以设\(dp[i][j]\)表示到了第\(i\ ...