Description

有N个位置,M个操作。操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c

如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是多少。

Input

第一行N,M

接下来M行,每行形如1 a b c或2 a b c

Output

输出每个询问的结果

Sample Input

2 5

1 1 2 1

1 1 2 2

2 1 1 2

2 1 1 1

2 1 2 3

Sample Output

1

2

1

HINT

【样例说明】



第一个操作 后位置 1 的数只有 1 , 位置 2 的数也只有 1 。 第二个操作 后位置 1



的数有 1 、 2 ,位置 2 的数也有 1 、 2 。 第三次询问 位置 1 到位置 1 第 2 大的数 是



1 。 第四次询问 位置 1 到位置 1 第 1 大的数是 2 。 第五次询问 位置 1 到位置 2 第 3



大的数是 1 。‍


N,M<=50000,N,M<=50000



a<=b<=N



1操作中abs(c)<=N



2操作中c<=Maxlongint

题解

不得不承认我真是太弱了,怼了这题几天,最后一个点还特判过的。。
不过终于解决这道难题,收货颇丰【QAQ蒟蒻的自我安慰】

首先说一下最容易想到的树套树做法
要求第k大,我们先权值取反,变为求第k小
先建一棵树维护每个权值出现的次数,这棵树并不是真的存在,它储存的只是另一棵树的根节点,对于根节点建一棵关于区间的线段树,表示权值[a,b]在区间[l,r]出现的次数
这样我们就可以通过二分求出[l,r]区间内的第k小数

例如我们要求[1,10]内第5小的数【假设总权值为[1,100]】
我们现在权值[1,50]的区间的根节点所在线段树询问[1,10]内的值,表示[1,50]权值在[1,10]这个区间内出现过多少次,
如果大于5,说明[1,10]区间内第k小一定在[1,50]权值内,
同理,我们在[1,25]找,一直到区间长度为1,即为答案

修改就更简单了,找到对应区间的树进行区间修改就好了


但正解不是树套树
正解是      整体二分 + 线段树


我们按顺序先存下所有的询问与修改,然后以权值为关键字进行二分,建立一棵关于区间出现次数的线段树
每次我们将一半的权值添加对线段树进行修改,就可以的出当前任意区间内该部分权值出现的次数,就可以对所有的询问进行二分了

对于区间[l,r],我们找到中间的mid值,然后从左开始扫描操作
1、如果是修改 且 权值大于mid,那么属于[mid + 1,r]范围内的权值,在线段树中[a,b]区间整体+1,表示[mid + 1,r]在区间[a,b]个出现了一次,然后放到相应的左边右边
2、如果是询问,我们看看当前[a,b]区间[mid + 1,r]权值出现的次数,如果大于c,说明在答案在该区间内,放到右边,否则放到左边
3、所有处理完后,对左右区间再二分,直至区间长度为1,得到答案



下面是树套树【没有A】
  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstring>
  4. #include<algorithm>
  5. #define LL long long int
  6. #define REP(i,n) for (int i = 1; i <= (n); i++)
  7. #define fo(i,x,y) for (int i = (x); i <= (y); i++)
  8. #define Redge(u) for (int k = head[u]; k != -1; k = edge[k].next)
  9. using namespace std;
  10. const int maxn = 400005,maxm = 20000005,INF = 1000000000;
  11.  
  12. inline int read(){
  13. int out = 0,flag = 1;char c = getchar();
  14. while (c < 48 || c > 57) {if (c == '-') flag = -1; c = getchar();}
  15. while (c >= 48 && c <= 57) {out = out * 10 + c - 48; c = getchar();}
  16. return out * flag;
  17. }
  18.  
  19. int a,b,c,N;
  20. int n,m,siz = 0;
  21. int rt[maxn];
  22. int ls[maxm],rs[maxm],sum[maxm],lazy[maxm],L,R;
  23.  
  24. inline void pd(int u,int l,int r){
  25. if (!lazy[u] || l == r) return;
  26. if (!ls[u]) ls[u] = ++siz;
  27. if (!rs[u]) rs[u] = ++siz;
  28. lazy[ls[u]] += lazy[u]; lazy[rs[u]] += lazy[u];
  29. int mid = l + r >> 1;
  30. sum[ls[u]] += lazy[u] * (mid - l + 1);
  31. sum[rs[u]] += lazy[u] * (r - mid);
  32. lazy[u] = 0;
  33. }
  34.  
  35. void modify(int& u,int l,int r){
  36. if (!u) u = ++siz;
  37. if (l >= L && r <= R){
  38. sum[u] += (r - l + 1);
  39. lazy[u]++;
  40. }else {
  41. pd(u,l,r);
  42. int mid = l + r >> 1;
  43. if (mid >= L) modify(ls[u],l,mid);
  44. if (mid < R) modify(rs[u],mid + 1,r);
  45. sum[u] = sum[ls[u]] + sum[rs[u]];
  46. }
  47. }
  48.  
  49. int Query(int u,int l,int r){
  50. if (!u) return 0;
  51. if (l >= L && r <= R) return sum[u];
  52. else {
  53. pd(u,l,r);
  54. int mid = l + r >> 1;
  55. if (mid >= R) return Query(ls[u],l,mid);
  56. else if (mid < L) return Query(rs[u],mid + 1,r);
  57. else return Query(ls[u],l,mid) + Query(rs[u],mid + 1,r);
  58. }
  59. }
  60.  
  61. inline void insert(){
  62. int u = 1,l = 1,r = N;
  63. L = a; R = b;
  64. while (l < r){
  65. int mid = l + r >> 1;
  66. modify(rt[u],1,n);
  67. if (c <= mid) r = mid,u = u << 1;
  68. else l = mid + 1,u = u << 1 | 1;
  69. }
  70. modify(rt[u],1,n);
  71. }
  72.  
  73. inline void solve(){
  74. int u = 1,l = 1,r = N,t;
  75. L = a; R = b;
  76. while (l < r){
  77. int mid = l + r >> 1;
  78. t = Query(rt[u << 1],1,n);
  79. if (c <= t) r = mid,u = u << 1;
  80. else l = mid + 1,u = u << 1 | 1,c -= t;
  81. }
  82. printf("%d\n",N - l + 1 - n);
  83. }
  84.  
  85. int main()
  86. {
  87. int cmd;
  88. n = read(); m = read();N = n * 2 + 1;
  89. while (m--){
  90. cmd = read(); a = read(); b = read(); c = read();
  91. if (cmd & 1){
  92. c += n;
  93. c = N - c + 1;
  94. insert();
  95. }else solve();
  96. }
  97. return 0;
  98. }


正解,整体二分【特判了一下。。。】
  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstring>
  4. #include<algorithm>
  5. #define LL long long int
  6. #define REP(i,n) for (int i = 1; i <= (n); i++)
  7. #define fo(i,x,y) for (int i = (x); i <= (y); i++)
  8. #define Redge(u) for (int k = head[u]; k != -1; k = edge[k].next)
  9. using namespace std;
  10. const int maxn = 500005,maxm = 100005,INF = 1000000000;
  11. //begin 18:00 end 19:27
  12. inline int read(){
  13. int out = 0,flag = 1;char c = getchar();
  14. while (c < 48 || c > 57) {if (c == '-') flag = -1; c = getchar();}
  15. while (c >= 48 && c <= 57) {out = out * 10 + c - 48; c = getchar();}
  16. return out * flag;
  17. }
  18.  
  19. int n,M;
  20.  
  21. struct node{
  22. int l,r,v,p,id,k;
  23. }e[maxn];
  24.  
  25. inline bool cmp(const node& a,const node& b){
  26. return a.k == b.k ? a.id < b.id : a.k < b.k;
  27. }
  28.  
  29. int ans[maxn];
  30. int sum[4 * maxn],lazy[4 * maxn],L,R;
  31. bool cl[4 * maxn];
  32.  
  33. inline void pd(int u,int l,int r){
  34. if (cl[u]) sum[u<<1] = sum[u<<1|1] = lazy[u<<1] = lazy[u<<1|1] = cl[u] = 0,cl[u<<1] = cl[u<<1|1] = true;
  35. if (lazy[u]){
  36. int mid = l + r >> 1;
  37. sum[u<<1] += (mid - l + 1) * lazy[u];
  38. sum[u<<1|1] += (r - mid) * lazy[u];
  39. lazy[u<<1] += lazy[u];
  40. lazy[u<<1|1] += lazy[u];
  41. lazy[u] = 0;
  42. }
  43. }
  44.  
  45. inline void update(int u,int l,int r){
  46. pd(u,l,r);
  47. if (l >= L && r <= R){
  48. sum[u] += (r - l + 1);
  49. lazy[u]++;
  50. }
  51. else {
  52. int mid = l + r >> 1;
  53. if (mid >= L) update(u<<1,l,mid);
  54. if (mid < R) update(u<<1|1,mid + 1,r);
  55. sum[u] = sum[u<<1] + sum[u<<1|1];
  56. }
  57. }
  58.  
  59. inline int Query(int u,int l,int r){
  60. pd(u,l,r);
  61. if (l >= L && r <= R) return sum[u];
  62. else {
  63. int mid = l + r >> 1;
  64. if (mid >= R) return Query(u<<1,l,mid);
  65. else if (mid < L) return Query(u<<1|1,mid + 1,r);
  66. else return Query(u<<1,l,mid) + Query(u<<1|1,mid + 1,r);
  67. }
  68. }
  69.  
  70. void solve(int l,int r,int el,int er){
  71. if (el > er) return;
  72. if (l == r){
  73. for (int i = el; i <= er; i++)
  74. if (e[i].p == 2) ans[e[i].id] = l;
  75. }
  76. else {
  77. cl[1] = true; sum[1] = lazy[1] = 0;
  78. int mid = (l + r) >> 1,i = el - 1,t;
  79. for (int k = el; k <= er; k++){
  80. if (e[k].p == 1){
  81. if (e[k].v > mid){
  82. L = e[k].l; R = e[k].r;
  83. update(1,1,n);
  84. e[k].k = 1;
  85. }else {
  86. e[k].k = 0;
  87. i++;
  88. }
  89. }
  90. else {
  91. L = e[k].l; R = e[k].r;
  92. t = Query(1,1,n);
  93. if (e[k].v <= t) e[k].k = 1;
  94. else {
  95. e[k].v -= t;
  96. e[k].k = 0;
  97. i++;
  98. }
  99. }
  100. }
  101. sort(e + el,e + er + 1,cmp);
  102. solve(l,mid,el,i);
  103. solve(mid + 1,r,i + 1,er);
  104. }
  105. }
  106.  
  107. void init(){
  108. n = read(); M = read();
  109. REP(i,M){
  110. e[i].p = read();
  111. e[i].l = read();
  112. e[i].r = read();
  113. e[i].v = read();
  114. if (e[i].p == 1) e[i].v = e[i].v + n;
  115. e[i].id = i;
  116. }
  117. memset(ans,-1,sizeof(ans));
  118. }
  119.  
  120. void print(){
  121. for (int i = 1; i <= M; i++)
  122. if (ans[i] != -1) {
  123. if (ans[i] == n) printf("50000\n");
  124. else printf("%d\n",ans[i] - n);
  125. }
  126. }
  127.  
  128. int main()
  129. {
  130. init();
  131. solve(0,2 * n,1,M);
  132. print();
  133. return 0;
  134. }


BZOJ3110 K大数查询 【线段树 + 整体二分 或 树套树(非正解)】的更多相关文章

  1. bzoj3110 [Zjoi2013]K大数查询——线段树套线段树

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3110 外层权值线段树套内层区间线段树: 之所以外层权值内层区间,是因为区间线段树需要标记下传 ...

  2. bzoj 3110 [Zjoi2013]K大数查询——线段树套线段树(标记永久化)

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3110 第一道线段树套线段树! 第一道标记永久化! 为什么为什么写了两个半小时啊…… 本想线段 ...

  3. 【BZOJ-3110】K大数查询 整体二分 + 线段树

    3110: [Zjoi2013]K大数查询 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 6265  Solved: 2060[Submit][Sta ...

  4. BZOJ3110[Zjoi2013]K大数查询(树状数组+整体二分)

    3110 [Zjoi2013]K大数查询 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c如果是2 a b c形式,表示询问从第a ...

  5. 【BZOJ3110】K大数查询(整体二分)

    [BZOJ3110]K大数查询(整体二分) 题面 BZOJ 题解 看了很久整体二分 一直不知道哪里写错了 ... 又把树状数组当成线段树区间加法来用了.. 整体二分还是要想清楚在干什么: 我们考虑第\ ...

  6. BZOJ_3110_[Zjoi2013]K大数查询_整体二分+树状数组

    BZOJ_3110_[Zjoi2013]K大数查询_整体二分+树状数组 Description 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位 ...

  7. BZOJ 3110 [Zjoi2013]K大数查询(整体二分)

    3110: [Zjoi2013]K大数查询 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 11654  Solved: 3505[Submit][St ...

  8. bzoj 3110: [Zjoi2013]K大数查询 树状数组套线段树

    3110: [Zjoi2013]K大数查询 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 1384  Solved: 629[Submit][Stat ...

  9. BZOJ 3110([Zjoi2013]K大数查询-区间第k大[段修改,在线]-树状数组套函数式线段树)

    3110: [Zjoi2013]K大数查询 Time Limit: 20 Sec   Memory Limit: 512 MB Submit: 418   Solved: 235 [ Submit][ ...

随机推荐

  1. JS基础,课堂作业,成绩练习

    成绩练习 <script> var name = prompt("请输入学生姓名:"); var degree = parseInt(prompt("请输入学 ...

  2. Android 测试 之MonkeyRunner

    一.什么是MonkeyRunner monkeyrunner工具提供了一个API,使用此API写出的程序可以在Android代码之外控制Android设备和模拟器.通过monkeyrunner,您可以 ...

  3. ip route ifconfig 基本命令

    1.route命令 route –n route add –net 192.168.2.0/24 dev eth0 route add –net 192.168.2.0 netmask 255.255 ...

  4. day06 再谈编码 and 作业讲解

    1. 小数据池,(其他语言又叫常量池) id() 查看变量的内存地址 is和== is 判断内存地址是否一致 == 判断内容是否一致 小数据池的作用: 为了快速的创建字符串对象, 可以减少内存的浪费 ...

  5. 软银集团和共享办公空间公司WeWork在日本成立合资公司

    [TechWeb报道]7月18日消息,据国外媒体报道,软银集团和共享办公空间公司WeWork联合宣布,在日本成立合资公司WeWork Japan. 该合资公司将在日本开设联合办公空间,于明年初在东京设 ...

  6. Python 装饰器Decorator(一)

    (一) 装饰器基础知识 什么是Python装饰器?Python里装饰器是一个可调用的对象(函数),其参数是另一个函数(被装饰的函数) 假如有一个名字为somedecorator的装饰器,target是 ...

  7. zend安装及破解

    Zend下载 https://pan.baidu.com/s/1fCfUQ0j7dxEtOzbNnsgODg 破解: 1.打开dmg文件安装,将Zend Studio拖拽至applications进行 ...

  8. Arctic Network POJ 2349 (最小生成树思想)

    Description The Department of National Defence (DND) wishes to connect several northern outposts by ...

  9. C++:const_cast的简单理解

    前言:const_cast是我比较头疼的一个知识点,最近查阅了很多资料,也翻看了很多他人的博客,故在此将自己目前学习到的有关const_cast知识做一个简单的总结 一.什么是const_cast 简 ...

  10. pandas中DataFrame的ix,loc,iloc索引方式的异同

    pandas中DataFrame的ix,loc,iloc索引方式的异同 1.loc: 按照标签索引,范围包括start和end 2.iloc: 在位置上进行索引,不包括end 3.ix: 先在inde ...