题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3110

外层权值线段树套内层区间线段树;

之所以外层权值内层区间,是因为区间线段树需要标记下传,所以写在内层比较方便;

然而空间太大了,所以动态开点,大约每个外层线段树的点上有 logn 个内层线段树点;

最开始写的不知为何很快就WA:

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstring>
  4. #include<algorithm>
  5. using namespace std;
  6. typedef long long ll;
  7. int const maxn=5e4+,maxm=maxn*;
  8. int n,m,rt[maxn<<],ls[maxm],rs[maxm],cnt;
  9. int a[maxn],b[maxn],tp[maxn],c[maxn],tmp[maxn],tot;
  10. ll sum[maxm],lzy[maxm];//ll lzy 防止计算时爆int
  11. void pushdown(int x,int l,int r)
  12. {
  13. if(!lzy[x])return;
  14. if(!ls[x])ls[x]=++cnt;
  15. if(!rs[x])rs[x]=++cnt;
  16. int mid=((l+r)>>);
  17. sum[ls[x]]+=(mid-l+)*lzy[x]; sum[rs[x]]+=(r-mid)*lzy[x];
  18. lzy[ls[x]]+=lzy[x]; lzy[rs[x]]+=lzy[x];
  19. lzy[x]=;
  20. }
  21. void add(int &x,int l,int r,int L,int R)
  22. {
  23. if(!x)x=++cnt;
  24. if(l>=L&&r<=R){sum[x]+=(r-l+); lzy[x]++; return;}
  25. // pushdown(x,l,r);
  26. int mid=((l+r)>>);
  27. if(mid>=L)add(ls[x],l,mid,L,R);
  28. if(mid<R)add(rs[x],mid+,r,L,R);
  29. sum[x]=sum[ls[x]]+sum[rs[x]];
  30. }
  31. void insert(int x,int l,int r,int tl,int tr,int c)
  32. {
  33. add(rt[x],,n,tl,tr);
  34. if(l==r)return;//
  35. int mid=((l+r)>>);//权值区间
  36. if(c<=mid)insert(x<<,l,mid,tl,tr,c);
  37. else insert(x<<|,mid+,r,tl,tr,c);
  38. }
  39. ll ask(int x,int l,int r,int L,int R)
  40. {
  41. if(!x)return ;//
  42. if(l>=L&&r<=R)return sum[x];
  43. pushdown(x,l,r);
  44. int mid=((l+r)>>); ll ret=;
  45. // if(mid>=L)ret+=ask(x<<1,l,mid,L,R);
  46. // if(mid<R)ret+=ask(x<<1|1,mid+1,r,L,R);
  47. if(mid>=L)ret+=ask(ls[x],l,mid,L,R);
  48. if(mid<R)ret+=ask(rs[x],mid+,r,L,R);//别写串了!
  49. return ret;
  50. }
  51. int query(int x,int l,int r,int L,int R,int k)
  52. {
  53. if(l==r)return l;
  54. ll tmp=ask(rt[x<<|],,n,L,R),mid=((l+r)>>);//查询第k大
  55. if(tmp>=k)return query(x<<|,mid+,r,L,R,k);//
  56. else return query(x<<,l,mid,L,R,k-tmp);//
  57. }
  58. int main()
  59. {
  60. scanf("%d%d",&n,&m);
  61. for(int i=;i<=m;i++)
  62. {
  63. scanf("%d%d%d%d",&tp[i],&a[i],&b[i],&c[i]);
  64. if(tp[i]==)tmp[++tot]=c[i];
  65. }
  66. sort(tmp+,tmp+n+); tot=unique(tmp+,tmp+n+)-tmp-;
  67. for(int i=;i<=m;i++)
  68. {
  69. if(tp[i]==)
  70. {
  71. int tt=lower_bound(tmp+,tmp+tot+,c[i])-tmp;
  72. insert(,,tot,a[i],b[i],tt);
  73. }
  74. else printf("%d\n",tmp[query(,,tot,a[i],b[i],c[i])]);
  75. }
  76. return ;
  77. }

不会改了,所以模仿别人写了个标记永久化,然后WA惨;

因为不太熟悉标记永久化,没注意到更新以及查询时要注意不能重复,改了半天,终于好了...

学到了点标记永久化的细节。

代码如下:

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstring>
  4. #include<algorithm>
  5. using namespace std;
  6. typedef long long ll;
  7. int const maxn=5e4+,maxm=maxn*;
  8. int n,m,rt[maxn<<],ls[maxm],rs[maxm],cnt;
  9. int a[maxn],b[maxn],tp[maxn],c[maxn],tmp[maxn],tot,L,R;
  10. ll sum[maxm],lzy[maxm];//ll lzy 防止计算时爆int
  11. //void pushdown(int x,int l,int r)
  12. //{
  13. // if(!lzy[x])return;
  14. // if(!ls[x])ls[x]=++cnt;
  15. // if(!rs[x])rs[x]=++cnt;
  16. // int mid=((l+r)>>1);
  17. // sum[ls[x]]+=(mid-l+1)*lzy[x]; sum[rs[x]]+=(r-mid)*lzy[x];
  18. // lzy[ls[x]]+=lzy[x]; lzy[rs[x]]+=lzy[x];
  19. // lzy[x]=0;
  20. //}
  21. void add(int &x,int l,int r,int L,int R)
  22. {
  23. if(!x)x=++cnt;
  24. if(l==L&&r==R){/*sum[x]+=(r-l+1);*/ lzy[x]++; return;}//==
  25. sum[x]+=(R-L+);
  26. // pushdown(x,l,r);
  27. int mid=((l+r)>>);
  28. // if(mid>=L)add(ls[x],l,mid,L,R);//会重复计算sum!(因为标记永久化)
  29. // if(mid<R)add(rs[x],mid+1,r,L,R);
  30. // sum[x]=sum[ls[x]]+sum[rs[x]];
  31. if(mid<L)add(rs[x],mid+,r,L,R);
  32. else if(mid>=R)add(ls[x],l,mid,L,R);
  33. else add(ls[x],l,mid,L,mid),add(rs[x],mid+,r,mid+,R);
  34. }
  35. ll ask(int x,int l,int r,int L,int R)
  36. {
  37. if(!x)return ;//
  38. ll ret=lzy[x]*(R-L+);
  39. if(l==L&&r==R)return ret+sum[x];//
  40. // pushdown(x,l,r);
  41. int mid=((l+r)>>);
  42. // if(mid>=L)ret+=ask(x<<1,l,mid,L,R);
  43. // if(mid<R)ret+=ask(x<<1|1,mid+1,r,L,R);//别把ls,rs和x<<1,x<<1|1写串了!
  44. // if(mid>=L)ret+=ask(ls[x],l,mid);
  45. // if(mid<R)ret+=ask(rs[x],mid+1,r); //会重复计算!!
  46. // printf("ret=%lld\n",ret);
  47. if(mid<L)return ret+ask(rs[x],mid+,r,L,R);
  48. else if(mid>=R)return ret+ask(ls[x],l,mid,L,R);
  49. else return ret+ask(ls[x],l,mid,L,mid)+ask(rs[x],mid+,r,mid+,R);
  50. }
  51. int query(int x,int l,int r,int k)
  52. {
  53. if(l==r)return l;
  54. ll tmp=ask(rt[x<<|],,n,L,R),mid=((l+r)>>);//查询第k大
  55. if(tmp>=k)return query(x<<|,mid+,r,k);//
  56. else return query(x<<,l,mid,k-tmp);//
  57. }
  58. void insert(int x,int l,int r,int c)
  59. {
  60. add(rt[x],,n,L,R);
  61. if(l==r)return;//
  62. int mid=((l+r)>>);//权值区间
  63. if(c<=mid)insert(x<<,l,mid,c);
  64. else insert(x<<|,mid+,r,c);
  65. }
  66. int main()
  67. {
  68. scanf("%d%d",&n,&m);
  69. for(int i=;i<=m;i++)
  70. {
  71. scanf("%d%d%d%d",&tp[i],&a[i],&b[i],&c[i]);
  72. if(tp[i]==)tmp[++tot]=c[i];
  73. }
  74. sort(tmp+,tmp+n+); tot=unique(tmp+,tmp+n+)-tmp-;
  75. for(int i=;i<=m;i++)
  76. {
  77. L=a[i],R=b[i];
  78. if(tp[i]==)
  79. {
  80. int tt=lower_bound(tmp+,tmp+tot+,c[i])-tmp;
  81. insert(,,tot,tt);
  82. }
  83. else printf("%d\n",tmp[query(,,tot,c[i])]);
  84. }
  85. return ;
  86. }

bzoj3110 [Zjoi2013]K大数查询——线段树套线段树的更多相关文章

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

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

  2. bzoj3110: [Zjoi2013]K大数查询 【树套树,标记永久化】

    //========================== 蒟蒻Macaulish:http://www.cnblogs.com/Macaulish/  转载要声明! //=============== ...

  3. BZOJ3110 [Zjoi2013]K大数查询 树套树 线段树 整体二分 树状数组

    欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ3110 题意概括 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位 ...

  4. BZOJ3110[Zjoi2013]K大数查询——权值线段树套线段树

    题目描述 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是 ...

  5. bzoj3110: [Zjoi2013]K大数查询 【cdq分治&树套树】

    模板题,折腾了许久. cqd分治整体二分,感觉像是把询问分到答案上. #include <bits/stdc++.h> #define rep(i, a, b) for (int i = ...

  6. 【BZOJ3110】K大数查询(权值线段树套线段树+标记永久化,整体二分)

    题意:有N个位置,M个操作.操作有两种,每次操作 如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c 如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是 ...

  7. [BZOJ3110] [Zjoi2013] K大数查询 (树套树)

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

  8. BZOJ3110: [Zjoi2013]K大数查询

    喜闻乐见的简单树套树= =第一维按权值建树状数组,第二维按下标建动态开点线段树,修改相当于第二维区间加,查询在树状数组上二分,比一般的线段树还短= =可惜并不能跑过整体二分= =另外bzoj上的数据有 ...

  9. 【树套树】bzoj3110 [Zjoi2013]K大数查询

    题解很多,实现起来以外地简洁.内层的区间线段树上用了标记永久化. #include<cstdio> using namespace std; #define N 50001 struct ...

随机推荐

  1. MariaDB常用命令手记

    创建用户命令 mysql>create user username@localhost identified by 'password'; 直接创建用户并授权的命令 mysql>grant ...

  2. html5——多列布局

    基本概念 1.多列布局类似报纸或杂志中的排版方式,上要用以控制大篇幅文本. 2.跨列属性可以控制横跨列的数量 /*列数*/ -webkit-column-count: ; /*分割线*/ -webki ...

  3. 【转】SSH中 整合spring和proxool 连接池

    [摘要:比来做的一个项目中应用到了毗邻池技巧,大概我们人人比拟认识的开源毗邻池有dbcp,c3p0,proxool.对那三种毗邻池来讲,从机能战失足率来讲,proxool轻微比前两种好些.本日我首要简 ...

  4. bootstrap table 生成的表格里动态添加HTML元素按钮,JS中添加点击事件,点击没反应---解决办法

    bootstraptable中onExpandRow属性---js  方法添加的 html代码,然后给这代码里面的 元素 添加 事件,却获取不该元素.(称之为未来元素),由于是未来的 所以现在没有这个 ...

  5. modelsim 仿真软件 百度云分享 modelsim se 10.7 10.6d 10.6c 10.5 10.4

    modelsim se 10.7 链接:https://pan.baidu.com/s/1NDC2yMCZmA4bIRSk2dUiTg 提取码:4l1d 复制这段内容后打开百度网盘手机App,操作更方 ...

  6. PHP中的几个随机数生成函数

    PHP中的几个随机数生成函数 rand() 基于 libc 的随机种子发生器 mt_rand() 基于 Mersenne Twister 算法返回随机整数.它可以产生随机数值的平均速度比 libc 提 ...

  7. 小白两篇博客熟练操作MySQL 之 第二篇

    小白两篇博客熟练操作MySQL  之   第二篇 一. 视图 视图是一个虚拟表,其本质是根据SQL语句获取动态的数据集,并为其命名,用户使用时只需使用名称即可获取结果集, 并可以将其当做表来使用. s ...

  8. 第三节:numpy之数组数学运算

  9. 2.1 Java开发工具包

        Java专业术语                   术语名   缩写                                                             ...

  10. 第2章 Python序列

    Python序列类似于C或Basic中的一维.多维数组等,但功能要强大很多,使用也更加灵活.方便,Head First Python一书就戏称列表是“打了激素”的数组. Python中常用的序列结构有 ...