【bzoj2989】数列 KD-tree+旋转坐标系
题目描述
输入
输出
对于每次询问操作,输出一个非负整数表示答案
样例输入
3 5
2 4 3
Query 2 2
Modify 1 3
Query 2 2
Modify 1 2
Query 1 1
样例输出
2
3
3
题解
KD-tree+旋转坐标系
这里的“可持久化”是逗你玩的,实际上操作只有两种:在平面上加一个点、在平面上查询到一个点曼哈顿距离不超过k的点的个数。
KD-tree就可以搞,然而这样做会TLE,因为查询斜正方形时间复杂度无法保证。
所以考虑把所有的点绕着原点逆时针旋转45度,查询的就是一个矩形空间,就可以直接使用KD-tree。
根据数学知识可知点$(x,y)$旋转后变为点$(\frac{x-y}{\sqrt 2},\frac{x+y}{\sqrt 2})$,可以把所有的$\sqrt 2$约掉,变为$(x-y,x+y)$。
查询时查的就是与某点切比雪夫距离不超过k(一个正方形范围)的点的个数。
亲测不加重构跑得比加重构还快,所以不用加了。
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#define N 100010
using namespace std;
int d , root , g[N];
char str[10];
struct data
{
int p[2] , mx[2] , mn[2] , sum , c[2];
bool operator<(data a)const {return p[d] == a.p[d] ? p[d ^ 1]< a.p[d ^ 1] : p[d] < a.p[d];}
}a[N];
void pushup(int x)
{
int l = a[x].c[0] , r = a[x].c[1];
a[x].mx[0] = max(a[x].p[0] , max(a[l].mx[0] , a[r].mx[0]));
a[x].mx[1] = max(a[x].p[1] , max(a[l].mx[1] , a[r].mx[1]));
a[x].mn[0] = min(a[x].p[0] , min(a[l].mn[0] , a[r].mn[0]));
a[x].mn[1] = min(a[x].p[1] , min(a[l].mn[1] , a[r].mn[1]));
a[x].sum = a[l].sum + a[r].sum + 1;
}
int build(int l , int r , int now)
{
int mid = (l + r) >> 1;
d = now , nth_element(a + l , a + mid , a + r + 1);
a[mid].c[0] = a[mid].c[1] = 0;
if(l < mid) a[mid].c[0] = build(l , mid - 1 , now ^ 1);
if(r > mid) a[mid].c[1] = build(mid + 1 , r , now ^ 1);
pushup(mid);
return mid;
}
void insert(int &k , int x)
{
if(!k) k = x;
else if(a[x] < a[k]) d ^= 1 , insert(a[k].c[0] , x);
else d ^= 1 , insert(a[k].c[1] , x);
pushup(k);
}
int judge(int k , int x1 , int y1 , int x2 , int y2)
{
if(!k || a[k].mx[0] < x1 || a[k].mx[1] < y1 || a[k].mn[0] > x2 || a[k].mn[1] > y2) return -1;
if(a[k].mn[0] >= x1 && a[k].mn[1] >= y1 && a[k].mx[0] <= x2 && a[k].mx[1] <= y2) return 1;
return 0;
}
int query(int k , int x1 , int y1 , int x2 , int y2)
{
int tmp = judge(k , x1 , y1 , x2 , y2);
if(tmp == 1) return a[k].sum;
if(tmp == -1) return 0;
int ans = (a[k].p[0] >= x1 && a[k].p[1] >= y1 && a[k].p[0] <= x2 && a[k].p[1] <= y2);
return ans + query(a[k].c[0] , x1 , y1 , x2 , y2) + query(a[k].c[1] , x1 , y1 , x2 , y2);
}
int main()
{
a[0].mx[0] = a[0].mx[1] = -1 << 30 , a[0].mn[0] = a[0].mn[1] = 1 << 30;
int n , m , i , x , y;
scanf("%d%d" , &n , &m);
for(i = 1 ; i <= n ; i ++ ) scanf("%d" , &g[i]) , a[i].p[0] = i - g[i] , a[i].p[1] = i + g[i];
root = build(1 , n , 0);
for(i = 1 ; i <= m ; i ++ )
{
scanf("%s%d%d" , str , &x , &y);
if(str[0] == 'M') g[x] = y , a[++n].p[0] = x - y , a[n].p[1] = x + y , insert(root , n);
else printf("%d\n" , query(root , x - g[x] - y , x + g[x] - y , x - g[x] + y , x + g[x] + y));
}
return 0;
}
【bzoj2989】数列 KD-tree+旋转坐标系的更多相关文章
- [bzoj2989]数列_KD-Tree_旋转坐标系
数列 bzoj-2989 题目大意:题目链接. 注释:略. 想法:显然,我们用x和a[x]两个值建立笛卡尔坐标系. 两个点之间的距离为曼哈顿距离. 修改操作就是插入... 查询操作就是查询一个点周围的 ...
- POJ3714 Raid 分治/K-D Tree
VJ传送门 简要题意:给出两个大小均为\(N\)的点集\(A,B\),试在\(A\)中选择一个点,在\(B\)中选择一个点,使得它们在所有可能的选择方案中欧几里得距离最小,求出这个距离 下面给出的两种 ...
- 【数据结构】K-D Tree
K-D Tree 这东西是我入坑 ICPC 不久就听说过的数据结构,但是一直没去学 QAQ,终于在昨天去学了它.还是挺好理解的,而且也有用武之地. 目录 简介 建树过程 性质 操作 例题 简介 K-D ...
- bzoj2989 数列(KDTree)
bzoj2989 数列(KDTree) bzoj 该说不愧是咱,一个月才水一篇题解然后还水的一批 题目描述: 给定一个长度为n的正整数数列a[i]. 定义2个位置的graze值为两者位置差与数值差的和 ...
- k-d tree 学习笔记
以下是一些奇怪的链接有兴趣的可以看看: https://blog.sengxian.com/algorithms/k-dimensional-tree http://zgjkt.blog.uoj.ac ...
- HDU2966 In case of failure(浅谈k-d tree)
嘟嘟嘟 题意:给定\(n\)个二维平面上的点\((x_i, y_i)\),求离每一个点最近的点得距离的平方.(\(n \leqslant 1e5\)) 这就是k-d tree入门题了. k-d tre ...
- AOJ DSL_2_C Range Search (kD Tree)
Range Search (kD Tree) The range search problem consists of a set of attributed records S to determi ...
- 【BZOJ-2648&2716】SJY摆棋子&天使玩偶 KD Tree
2648: SJY摆棋子 Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 2459 Solved: 834[Submit][Status][Discu ...
- K-D Tree
这篇随笔是对Wikipedia上k-d tree词条的摘录, 我认为解释得相当生动详细, 是一篇不可多得的好文. Overview A \(k\)-d tree (short for \(k\)-di ...
随机推荐
- Node.js 打造实时多人游戏框架
在 Node.js 如火如荼发展的今天,我们已经可以用它来做各种各样的事情.前段时间UP主参加了极客松活动,在这次活动中我们意在做出一款让“低头族”能够更多交流的游戏,核心功能便是 Lan Party ...
- HDU 5418 Victor and World (可重复走的TSP问题,状压dp)
题意: 每个点都可以走多次的TSP问题:有n个点(n<=16),从点1出发,经过其他所有点至少1次,并回到原点1,使得路程最短. 思路: 给了很多重边,选最小的留下即可.任意点可能无法直接到达, ...
- Gym 100342I Travel Agency (Tarjan)
题意读懂了就好做了,就是求一下点双连通分量.维护一下一颗子树的结点数,对于一个结点当u是割点的时候, 统计一下u分割的连通分量v,每得到一个连通分量的结点数cnt(v)和之前连通分量结点数sum相乘一 ...
- iOS开发资源:推送通知相关开源项目--PushSharp、APNS-PHP以及Pyapns等
PushSharp (github) PushSharp是一个实现了由服务器端向移动客户端推送消息的开源C#库,支持 iOS (iPhone/iPad APNS). Android (C2DM/GC ...
- Thread源码分析-java8
1.Thread特性分析 守护线程Daemon 定性:支持性线程,主要用于程序中后台调度以及支持性工作. 当JVM中不存在Daemon线程时,JVM将会退出. 将一个线程设定为Daemon的方法: 调 ...
- 基于Python的Web应用开发实战——3 模板
要想开发出易于维护的程序,关键在于编写形式简洁且结构良好的代码. 当目前为止,你看到的示例都太简单,无法说明这一点,但Flask视图函数的两个完全独立的作用却被融合在了一起,这就产生了一个问题. 视图 ...
- struct结构体内存大小
一. 基本原则 1. struct中成员变量的声明顺序,与成员变量对应的内存顺序是一致的: 2. struct本身的起始存储地址必须是成员变量中最长的数据类型的整倍数,注意是最长的数据类型,而不是最长 ...
- applicationContext.xml重要配置
<!-- 加载 hibernate.properties 文件--> <bean id="propertyConfig" class="org.spri ...
- 二分查找算法java
二分查找又称折半查找,它是一种效率较高的查找方法. 折半查找的算法思想是将数列按有序化(递增或递减)排列,查找过程中采用跳跃式方式查找,即先以有序数列的中点位置为比较对象,如果要找的元素值小于该中点元 ...
- glassfish配置中数据库密码加密方法
glassfish配置中数据库密码加密方法 Glassfish中的数据库连接池需要使用密文保存数据库密码.如果不是,则可按如下方法可配置 通过Glassfish中的Alias实现,配置方法如下: 1. ...