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之和最大的点就好了。
那么如何把所有的点转化到该查询的左下呢?
对于每个查询,可以把一、二、四象限的点都通过对称转移到第三象限。但查询很多,不可能一个个翻转。
换个思路,如果把整个平面翻转三次,进行四次cdq分治,每次都只考虑左下的点,所有的点就都遍历到了!
记录最大的x或y值为边界len,每次沿len翻转。例如沿y轴翻转时,x = len-x
那么每个操作有三维——时间、x坐标、y坐标
时间在输入时已经排好了;x归并排序;y仿照陌上花开,用树状数组记录。
优化 & 注意
这道题坑点超级多...而且四次cdq分治会得到一个感人的复杂度,所以必须考虑优化,卡一卡常数(我选择吸氧)
- cdq内的归并排序代替每次sort。
- 因为每次cdq完顺序会被打乱,如果重新按时间O(nlogn)排序,不如每次存入一个临时数组,然后O(n)直接复制过去。
但是ans需要存入初始的数组中,所以结构体需要一个.id来记录打乱前的时间,也就是原数组下标。赋值应该写a[b[t2].id].ans,而不是a[t2].ans。
并且,由于每次查询点的x,y也会更改,所以ans里不能直接存max(Bx+By),而应该为min((Ax+Ay)-(Bx+By))。
- 如果某个点在坐标轴上,那么它的x或y为0。存入树状数组时,会因为lowbit()==0而陷入死循环。所以存入时,将x,y分别+1。
同样的,如果某个点在翻转边界len上,翻转时也会变为0。所以len也要++。
- 考虑这样一种情况:某一点非常靠近边界,导致某次翻转时,没有点在它的左下。这样查询时默认返回了0。
当前的“原点”比实际上的点离该查询点更近,这样最终的距离就成了这个点到原点的距离,但原点是不存在的(经过刚刚的更改,已经没有x或y坐标为0的点)
为避免这种情况,当查询时需要特判,若为0则返回-INF。
- 由于初始值——前n个点一定是修改操作,可以把它们直接排好序,不用递归检验是否有查询。(不过我觉得有点麻烦就没写)
这道题的代码不难,但是细节特别多,很难debug...写的时候思路一定要清晰了!
代码如下
// luogu-judger-enable-o2
#include<cstdio>
#include<iostream>
#define MogeKo qwq
using namespace std;
const int maxn = 1e7+;
const int INF = 2e7+;
int n,q,opt,x,y,len; struct node {
int x,y,type,id,ans;
} a[maxn],b[maxn],tem[maxn]; struct BIT {
int m[maxn];
int lowbit(int x) {
return x & -x;
}
void update(int x,int v) {
for(; x <= len; x+= lowbit(x))
m[x] = max(m[x],v);
}
int query(int x) {
int ans = ;
for(; x; x-=lowbit(x))
ans = max(ans,m[x]);
return ans?ans:-INF;
}
void clear(int x) {
for(; m[x]; x+= lowbit(x))
m[x] = ;
}
} tree; void cdq(int L,int R) {
if(L == R) return;
int mid = L+R >> ;
cdq(L,mid),cdq(mid+,R);
int t1 = L,t2 = mid+;
int k = L;
while(t2 <= R) {
while(t1 <= mid && b[t1].x <= b[t2].x) {
if(b[t1].type == )
tree.update(b[t1].y, b[t1].x+b[t1].y);
tem[k++] = b[t1++];
}
if(b[t2].type == )
a[b[t2].id].ans = min(a[b[t2].id].ans,b[t2].x+b[t2].y-tree.query(b[t2].y));
tem[k++] = b[t2++];
}
for(int i = L; i <= t1-; i++)
if(b[i].type == ) tree.clear(b[i].y);
while(t1 <= mid) tem[k++] = b[t1++];
for(int i = L;i <= R;i++) b[i] = tem[i];
} void solve(int rx,int ry) {
for(int i = ; i <= n+q; i++) {
b[i] = a[i];
if(rx) b[i].x = len - b[i].x;
if(ry) b[i].y = len - b[i].y;
}
cdq(,n+q);
} int main() {
scanf("%d%d",&n,&q);
for(int i = ; i <= n; i++) {
scanf("%d%d",&x,&y);
a[i].type = ;
a[i].id = i;
a[i].x = ++x;
a[i].y = ++y;
len = max(len,max(x,y));
}
for(int i = n+; i <= n+q; i++) {
scanf("%d%d%d",&opt,&x,&y);
a[i].type = opt;
a[i].id = i;
a[i].x = ++x;
a[i].y = ++y;
a[i].ans = INF;
len = max(len,max(x,y));
}
len++;
solve(,),solve(,),solve(,),solve(,);
for(int i = n+; i <= n+q; i++)
if(a[i].type == ) printf("%d\n",a[i].ans);
return ;
}
Luogu P4169 [Violet]天使玩偶/SJY摆棋子的更多相关文章
- bzoj2716/2648 / P4169 [Violet]天使玩偶/SJY摆棋子
P4169 [Violet]天使玩偶/SJY摆棋子 k-d tree 模板 找了好几天才发现输出优化错了....真是zz...... 当子树非常不平衡时,就用替罪羊树的思想,拍扁重建. luogu有个 ...
- 洛谷 P4169 [Violet]天使玩偶/SJY摆棋子 解题报告
P4169 [Violet]天使玩偶/SJY摆棋子 题目描述 \(Ayu\)在七年前曾经收到过一个天使玩偶,当时她把它当作时间囊埋在了地下.而七年后 的今天,\(Ayu\) 却忘了她把天使玩偶埋在了哪 ...
- 洛谷P4169 [Violet]天使玩偶/SJY摆棋子(CDQ分治)
[Violet]天使玩偶/SJY摆棋子 题目传送门 解题思路 用CDQ分治开了氧气跑过. 将输入给的顺序作为第一维的时间,x为第二维,y为第三维.对于距离一个询问(ax,ay),将询问分为四块,左上, ...
- P4169 [Violet]天使玩偶/SJY摆棋子
题目背景 感谢@浮尘ii 提供的一组hack数据 题目描述 Ayu 在七年前曾经收到过一个天使玩偶,当时她把它当作时间囊埋在了地下.而七年后 的今天,Ayu 却忘了她把天使玩偶埋在了哪里,所以她决定仅 ...
- 洛谷P4169 [Violet]天使玩偶/SJY摆棋子
%%%神仙\(SJY\) 题目大意: 一个二维平面,有两种操作: \(1.\)增加一个点\((x,y)\) \(2.\)询问距离\((x,y)\)曼哈顿最近的一个点有多远 \(n,m\le 300 0 ...
- luoguP4169 [Violet]天使玩偶/SJY摆棋子 K-Dtree
P4169 [Violet]天使玩偶/SJY摆棋子 链接 luogu 思路 luogu以前用CDQ一直过不去. bzoj还是卡时过去的. 今天终于用k-dtree给过了. 代码 #include &l ...
- [Violet]天使玩偶/SJY摆棋子 [cdq分治]
P4169 [Violet]天使玩偶/SJY摆棋子 求离 \((x,y)\) 最近点的距离 距离的定义是 \(|x1-x2|+|y1-y2|\) 直接cdq 4次 考虑左上右上左下右下就可以了-略微卡 ...
- 【LG4169】[Violet]天使玩偶/SJY摆棋子
[LG4169][Violet]天使玩偶/SJY摆棋子 题面 洛谷 题解 至于\(cdq\)分治的解法,以前写过 \(kdTree\)的解法好像还\(sb\)一些 就是记一下子树的横.纵坐标最值然后求 ...
- LG4169 [Violet]天使玩偶/SJY摆棋子
题意 Ayu 在七年前曾经收到过一个天使玩偶,当时她把它当作时间囊埋在了地下.而七年后 的今天,Ayu 却忘了她把天使玩偶埋在了哪里,所以她决定仅凭一点模糊的记忆来寻找它. 我们把 Ayu 生活的小镇 ...
随机推荐
- Android智能指针SP WP使用方法介绍
Android手机操作系统既然是开源的操作系统.那么在具体的文件夹中就会存放着各种相关功能的开源代码.我们在使用的时候可以根据这些源代码进行相应的修改就能轻松的完成我们所需的功能.在这里大家就一起来看 ...
- 利用Selenium爬取淘宝商品信息
一. Selenium和PhantomJS介绍 Selenium是一个用于Web应用程序测试的工具,Selenium直接运行在浏览器中,就像真正的用户在操作一样.由于这个性质,Selenium也是一 ...
- 产品经理说| AIOps 让告警变得更智能 (下)
AIOps 人工智能和IT运营支撑 Ops 之间的故事,愈演愈烈,已经成为当今运维圈的热门话题,我打算从2篇文档分享我们在 AIOps 上一些探索和实践.(上篇)主要介绍了为什么事件(告警)处理需要 ...
- LeetCode题解之Clone Graph
1.题目描述 2.问题分析 要遍历图,然后标记没有被复制的节点. 3.代码 class Solution { private: unordered_map<Node*, Node*> m; ...
- SpringBoot Controller 中 HttpServletRequest ServletInputStream 读取不到数据该怎么处理
在Springboot程序启动后,会默认添加OrderedCharacterEncodingFilter和HiddenHttpMethodFilter过滤器.在HiddenHttpMethodFilt ...
- C#面向对象 类的继承
1.类的访问权限: public:跨程序集,命名空间,必须被using引用: internal:默认当前命名空间: 2.类成员的访问权限: private:私有的,只能当前类: protecte:受保 ...
- mssql sqlserver 使用sql脚本输出交替不同的背景色的html信息的方法分享
转自:http://www.maomao365.com/?p=6679 摘要: 下文将分享使用sql脚本输出交替变换的不同背景颜色的sql脚本的方法分享,如下所示: 实验环境:sqlserver 20 ...
- web前端(11)—— 页面布局1
要说页面布局的话,那就必须说说margin,padding,和background.这三个属性其实都是前面讲过的,这里还是再次讲解以下,为什么呢?因为是这样的,光靠前面的css样式来设置,你很可能会遇 ...
- Vue2 学习笔记5
文中例子代码请参考github watch属性的使用 考虑一个问题:想要实现 名 和 姓 两个文本框的内容改变,则全名的文本框中的值也跟着改变:(用以前的知识如何实现???) 监听data中属性的改变 ...
- ASYNC_NETWORK_IO和PREEMPTIVE_OS_WAITFORSINGLEOBJECT等待事件
背景环境: SQL Server 2005或以上 Select * from 某个表,表的数据量约为30万行,在执行语句时通过观察sys.dm_exec_requests中的wait_type列发现是 ...