题目描述

给定一个长度为n的正整数数列a[i]。
定义2个位置的graze值为两者位置差与数值差的和,即graze(x,y)=|x-y|+|a[x]-a[y]|。
2种操作(k都是正整数):
1.Modify x k:将第x个数的值修改为k。
2.Query x k:询问有几个i满足graze(x,i)<=k。因为可持久化数据结构的流行,询问不仅要考虑当前数列,还要
考虑任意历史版本,即统计任意位置上出现过的任意数值与当前的a[x]的graze值<=k的对数。(某位置多次修改为
同样的数值,按多次统计)

输入

第1行两个整数n,q。分别表示数列长度和操作数。
第2行n个正整数,代表初始数列。
第3--q+2行每行一个操作。

输出

对于每次询问操作,输出一个非负整数表示答案

样例输入

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(一个正方形范围)的点的个数。

亲测不加重构跑得比加重构还快,所以不用加了。

  1. #include <cstdio>
  2. #include <cmath>
  3. #include <cstring>
  4. #include <algorithm>
  5. #define N 100010
  6. using namespace std;
  7. int d , root , g[N];
  8. char str[10];
  9. struct data
  10. {
  11. int p[2] , mx[2] , mn[2] , sum , c[2];
  12. bool operator<(data a)const {return p[d] == a.p[d] ? p[d ^ 1]< a.p[d ^ 1] : p[d] < a.p[d];}
  13. }a[N];
  14. void pushup(int x)
  15. {
  16. int l = a[x].c[0] , r = a[x].c[1];
  17. a[x].mx[0] = max(a[x].p[0] , max(a[l].mx[0] , a[r].mx[0]));
  18. a[x].mx[1] = max(a[x].p[1] , max(a[l].mx[1] , a[r].mx[1]));
  19. a[x].mn[0] = min(a[x].p[0] , min(a[l].mn[0] , a[r].mn[0]));
  20. a[x].mn[1] = min(a[x].p[1] , min(a[l].mn[1] , a[r].mn[1]));
  21. a[x].sum = a[l].sum + a[r].sum + 1;
  22. }
  23. int build(int l , int r , int now)
  24. {
  25. int mid = (l + r) >> 1;
  26. d = now , nth_element(a + l , a + mid , a + r + 1);
  27. a[mid].c[0] = a[mid].c[1] = 0;
  28. if(l < mid) a[mid].c[0] = build(l , mid - 1 , now ^ 1);
  29. if(r > mid) a[mid].c[1] = build(mid + 1 , r , now ^ 1);
  30. pushup(mid);
  31. return mid;
  32. }
  33. void insert(int &k , int x)
  34. {
  35. if(!k) k = x;
  36. else if(a[x] < a[k]) d ^= 1 , insert(a[k].c[0] , x);
  37. else d ^= 1 , insert(a[k].c[1] , x);
  38. pushup(k);
  39. }
  40. int judge(int k , int x1 , int y1 , int x2 , int y2)
  41. {
  42. if(!k || a[k].mx[0] < x1 || a[k].mx[1] < y1 || a[k].mn[0] > x2 || a[k].mn[1] > y2) return -1;
  43. if(a[k].mn[0] >= x1 && a[k].mn[1] >= y1 && a[k].mx[0] <= x2 && a[k].mx[1] <= y2) return 1;
  44. return 0;
  45. }
  46. int query(int k , int x1 , int y1 , int x2 , int y2)
  47. {
  48. int tmp = judge(k , x1 , y1 , x2 , y2);
  49. if(tmp == 1) return a[k].sum;
  50. if(tmp == -1) return 0;
  51. int ans = (a[k].p[0] >= x1 && a[k].p[1] >= y1 && a[k].p[0] <= x2 && a[k].p[1] <= y2);
  52. return ans + query(a[k].c[0] , x1 , y1 , x2 , y2) + query(a[k].c[1] , x1 , y1 , x2 , y2);
  53. }
  54. int main()
  55. {
  56. a[0].mx[0] = a[0].mx[1] = -1 << 30 , a[0].mn[0] = a[0].mn[1] = 1 << 30;
  57. int n , m , i , x , y;
  58. scanf("%d%d" , &n , &m);
  59. for(i = 1 ; i <= n ; i ++ ) scanf("%d" , &g[i]) , a[i].p[0] = i - g[i] , a[i].p[1] = i + g[i];
  60. root = build(1 , n , 0);
  61. for(i = 1 ; i <= m ; i ++ )
  62. {
  63. scanf("%s%d%d" , str , &x , &y);
  64. if(str[0] == 'M') g[x] = y , a[++n].p[0] = x - y , a[n].p[1] = x + y , insert(root , n);
  65. else printf("%d\n" , query(root , x - g[x] - y , x + g[x] - y , x - g[x] + y , x + g[x] + y));
  66. }
  67. return 0;
  68. }

【bzoj2989】数列 KD-tree+旋转坐标系的更多相关文章

  1. [bzoj2989]数列_KD-Tree_旋转坐标系

    数列 bzoj-2989 题目大意:题目链接. 注释:略. 想法:显然,我们用x和a[x]两个值建立笛卡尔坐标系. 两个点之间的距离为曼哈顿距离. 修改操作就是插入... 查询操作就是查询一个点周围的 ...

  2. POJ3714 Raid 分治/K-D Tree

    VJ传送门 简要题意:给出两个大小均为\(N\)的点集\(A,B\),试在\(A\)中选择一个点,在\(B\)中选择一个点,使得它们在所有可能的选择方案中欧几里得距离最小,求出这个距离 下面给出的两种 ...

  3. 【数据结构】K-D Tree

    K-D Tree 这东西是我入坑 ICPC 不久就听说过的数据结构,但是一直没去学 QAQ,终于在昨天去学了它.还是挺好理解的,而且也有用武之地. 目录 简介 建树过程 性质 操作 例题 简介 K-D ...

  4. bzoj2989 数列(KDTree)

    bzoj2989 数列(KDTree) bzoj 该说不愧是咱,一个月才水一篇题解然后还水的一批 题目描述: 给定一个长度为n的正整数数列a[i]. 定义2个位置的graze值为两者位置差与数值差的和 ...

  5. k-d tree 学习笔记

    以下是一些奇怪的链接有兴趣的可以看看: https://blog.sengxian.com/algorithms/k-dimensional-tree http://zgjkt.blog.uoj.ac ...

  6. HDU2966 In case of failure(浅谈k-d tree)

    嘟嘟嘟 题意:给定\(n\)个二维平面上的点\((x_i, y_i)\),求离每一个点最近的点得距离的平方.(\(n \leqslant 1e5\)) 这就是k-d tree入门题了. k-d tre ...

  7. 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 ...

  8. 【BZOJ-2648&2716】SJY摆棋子&天使玩偶 KD Tree

    2648: SJY摆棋子 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 2459  Solved: 834[Submit][Status][Discu ...

  9. K-D Tree

    这篇随笔是对Wikipedia上k-d tree词条的摘录, 我认为解释得相当生动详细, 是一篇不可多得的好文. Overview A \(k\)-d tree (short for \(k\)-di ...

随机推荐

  1. Vue-router 的练习

    使用了vue-cli 生成了一套webpack的模版. 之后在其中练习 vue-router. 以下是一些记录. 1.动态路由的配置 import Vue from 'vue' import Rout ...

  2. OpenCV中CvMat的初始化[转]

    一)cvCreateMat创建和分配数据CvCreateMat会创建CvMat,并为CvMat分配数据.cvCreateMat可以配合cvInitMatHeader来初始化CvMat对象.因为CvCr ...

  3. 47.Number of Islands(岛的数量)

    Level:   Medium 题目描述: Given a 2d grid map of '1's (land) and '0's (water), count the number of islan ...

  4. Latex 分块矩阵的处理

    在 \(\mathrm{\LaTeX}\) 中,如果想输入类似的矩阵: 可以这样实现: \[ \left[ \begin{array}{cc|cc|c} \lambda & 0 & 1 ...

  5. CPP-基础:C++的new int()与new int[]

    编写一个List类: class List { int length; //列表长度 int* lpInt; //列表指针 List(int size); ~List(); } List::List( ...

  6. windows10 下安装、配置、启动mysql

    下载mysql 可以自行去百度 或者 https://dev.mysql.com/downloads/mysql/5.7.html#downloads 解压mysql-5.7.26-winx64.zi ...

  7. bootstrap 翻页(对齐的链接)

    <!DOCTYPE html><html><head><meta http-equiv="Content-Type" content=&q ...

  8. perl学习之裸字

    use strict包含3个部分.其中之一(use strict "subs")负责禁止乱用的裸字. 这是什么意思呢? 如果没有这个限制,下面的代码也可以打印出"hell ...

  9. Python的第3堂课

    20181119笔记 一.内存管理相关 ①Cpython解释器的垃圾回收机制 什么是垃圾:当一个值没有被绑定任何变量名(即该值的引用计数为零时),该值就是垃圾. 垃圾回收是收回值占用的内存空间. 引用 ...

  10. (转)UIPanGestureRecognizer

    UIPanGestureRecognizer是UIGestureRecognizer类的一个扩展类,其扩展类有UITapGestureRecognizer,UIPinchGestureRecogniz ...