题目链接:https://www.luogu.com.cn/problem/P2617

参考博客:https://blog.csdn.net/dreaming__ldx/article/details/80872728

在主席树的基础上实现单点更新也不困难,主要我们要明白主席树的函数性质,也就是一个根节点代表的信息我们可以认为是一段前缀,朴素主席树的T(i)树代表的是区间[1,i]的前缀,这样子单点更新之后就必须更新之后的T(i+1)~T(n)的线段树,这样的话时间复杂度非常高,我们可以利用主席树的函数性质,用树状数组套主席树,树状数组的C[i]点的主席树维护的是[i-lowbit(i)+1,i]区间的插入信息(虽然在根节点都是维护[1,n]区间),也就是T(i)树维护的是lowbit(i)长度的区间。每棵主席树维护的区间不是前缀区间,这个是树状数组套主席树的重点。所以更新的时候我们只要更新树状数组中的logn个结点,而在这每个结点之中我们需要修改一条链上的logn个结点(该结点属于主席树)。最终q次修改+m次查询的时间复杂度是O(q*log^2(n)+mlogn)。注意树状数组是建立在原数组的基础上的,所以树状数组中的索引与原数组的索引相关联,而主席树的索引则是离散值的索引,这与静态主席树相比又复杂了写,体现在add函数中,add函数传入的是实时原数组的索引,所以先修改位置的信息再通过这个位置获得修改的值的大小。

下面附上自写代码,结构体保存的树的信息,常数比较大:

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. typedef unsigned int ui;
  4. typedef long long ll;
  5. typedef unsigned long long ull;
  6. #define pf printf
  7. #define mem(a,b) memset(a,b,sizeof(a))
  8. #define prime1 1e9+7
  9. #define prime2 1e9+9
  10. #define pi 3.14159265
  11. #define lson l,mid,rt<<1
  12. #define rson mid+1,r,rt<<1|1
  13. #define scand(x) scanf("%llf",&x)
  14. #define f(i,a,b) for(int i=a;i<=b;i++)
  15. #define scan(a) scanf("%d",&a)
  16. #define mp(a,b) make_pair((a),(b))
  17. #define P pair<int,int>
  18. #define dbg(args) cout<<#args<<":"<<args<<endl;
  19. #define inf 0x3f3f3f3f
  20. const int maxn=1e5+;
  21. int n,m;
  22. inline int read(){
  23. int ans=,w=;
  24. char ch=getchar();
  25. while(!isdigit(ch)){if(ch=='-')w=-;ch=getchar();}
  26. while(isdigit(ch))ans=(ans<<)+(ans<<)+ch-'',ch=getchar();
  27. return ans*w;
  28. }
  29.  
  30. struct node{
  31. int l,r,sum;
  32. }t[maxn*];
  33. struct qu{
  34. int a,b,c;
  35. }q[maxn];
  36. int cnt=,tot;
  37. char s[];
  38. //root中存放主席树的根节点编号,b中存放的所有将会出现在数列中的数
  39. //b数组乘2是因为可能有1e5的原数据和1e5的更新点
  40. //a中存放的是数组的实时动态情况,一旦有点修改就会体现在a数组上
  41. int root[maxn*],b[maxn<<],a[maxn],qx[maxn],qy[maxn],ansx,ansy;
  42. //在pre结点的基础上,建立now根结点并且在p位置加上v
  43. //对每棵主席树的插入操作都是一样的,所以带修跟不带修的插入函数一样
  44. int lowbit(int x){return x&(-x);}
  45. void update(int l,int r,int pre,int &now,int p,int v)
  46. {
  47. t[++cnt]=t[pre];
  48. now=cnt;
  49. t[now].sum+=v;//(now结点的区间一定是包含p位置的)
  50. if(l==r)return;
  51. int m=l+r>>;//划分区间,决定向左子树还是右子树更新
  52. if(p<=m)update(l,m,t[pre].l,t[now].l,p,v);
  53. else update(m+,r,t[pre].r,t[now].r,p,v);
  54. }
  55. void add(int x,int v)//给第x个数插上v,这是在树套树的主席树上进行的加操作
  56. {//对于树状数组i位置上的主席树,根就是root[i]
  57. int k=lower_bound(b+,b+tot+,a[x])-b;
  58. for(int i=x;i<=n;i+=lowbit(i))update(,tot,root[i],root[i],k,v);//就在第i棵树上进行操作
  59. }
  60. int query(int l,int r,int k)
  61. {
  62. if(l==r)return l;
  63. int sum=,m=l+r>>;
  64. f(i,,ansy)sum+=t[t[qy[i]].l].sum;
  65. f(i,,ansx)sum-=t[t[qx[i]].l].sum;//计算[l,m]区间插入的数的数量
  66. if(k<=sum)
  67. {
  68. f(i,,ansx)qx[i]=t[qx[i]].l;
  69. f(i,,ansy)qy[i]=t[qy[i]].l;//同步、更新、递归
  70. return query(l,m,k);
  71. }
  72. else
  73. {
  74. f(i,,ansx)qx[i]=t[qx[i]].r;
  75. f(i,,ansy)qy[i]=t[qy[i]].r;
  76. return query(m+,r,k-sum);
  77. }
  78. }
  79. int main()
  80. {
  81. //freopen("input.txt","r",stdin);
  82. //freopen("output.txt","w",stdout);
  83. std::ios::sync_with_stdio(false);
  84. n=read(),m=read(),cnt=,tot=;
  85. f(i,,n){
  86. a[i]=b[++tot]=read();
  87. }
  88. f(i,,m)
  89. {
  90. scanf("%s",s);
  91. q[i].a=read(),q[i].b=read();
  92. if(s[]=='Q')q[i].c=read();
  93. else q[i].c=,b[++tot]=q[i].b;
  94. //离线处理
  95. }
  96. sort(b+,b+tot+);
  97. tot=unique(b+,b+tot+)-(b+);
  98. f(i,,n)add(i,);//将第i个数插入主席树
  99. f(i,,m)
  100. {
  101. if(q[i].c)
  102. {
  103. ansx=ansy=;
  104. for(int j=q[i].b;j;j-=lowbit(j))qy[++ansy]=root[j];//把需要查询的点的根节点的编号保存下来
  105. for(int j=q[i].a-;j;j-=lowbit(j))qx[++ansx]=root[j];
  106. pf("%d\n",b[query(,tot,q[i].c)]);//注意vector中下标从1开始
  107. }
  108. else
  109. {
  110. add(q[i].a,-);
  111. a[q[i].a]=q[i].b;//将点更新实时地在a上体现
  112. add(q[i].a,);
  113. }
  114. }
  115. }

带修主席树 洛谷2617 支持单点更新以及区间kth大查询的更多相关文章

  1. 【BZOJ-1146】网络管理Network DFS序 + 带修主席树

    1146: [CTSC2008]网络管理Network Time Limit: 50 Sec  Memory Limit: 162 MBSubmit: 3495  Solved: 1032[Submi ...

  2. P2617 Dynamic Rankings(带修主席树)

    所谓带修主席树,就是用树状数组的方法维护主席树的前缀和 思路 带修主席树的板子 注意数据范围显然要离散化即可 代码 #include <cstdio> #include <cstri ...

  3. 2018.07.01洛谷P2617 Dynamic Rankings(带修主席树)

    P2617 Dynamic Rankings 题目描述 给定一个含有n个数的序列a[1],a[2],a[3]--a[n],程序必须回答这样的询问:对于给定的i,j,k,在a[i],a[i+1],a[i ...

  4. 2018.07.01 BZOJ3295: [Cqoi2011]动态逆序对(带修主席树)

    3295: [Cqoi2011]动态逆序对 **Time Limit: 10 Sec Memory Limit: 128 MB Description 对于序列A,它的逆序对数定义为满足i<j& ...

  5. BZOJ1901 Dynamic Rankings|带修主席树

    题目链接:戳我 其实我并不会做,于是看了题解 我们都知道主席树是利用前缀和记录历史版本来搞区间K大的一种数据结构.不过一般的主席树只能搞定静态区间第K大.如果带修怎么办呢? 想一下...单点修改+区间 ...

  6. [luogu P2617] Dynamic Rankings 带修主席树

    带修改的主席树,其实这种,已经不能算作主席树了,因为这个没有维护可持久化的... 主席树直接带修改的话,由于这种数据结构是可持久化的,那么要相应改动,这个节点以后所有的主席树,这样单次修改,就达到n* ...

  7. 【BZOJ-1901】Dynamic Rankings 带修主席树

    1901: Zju2112 Dynamic Rankings Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 7292  Solved: 3038[Su ...

  8. Machine Learning Codeforces - 940F(带修莫队) && 洛谷P4074 [WC2013]糖果公园

    以下内容未验证,有错请指正... 设块大小为T,则块数为$\frac{n}{T}$ 将询问分为$(\frac{n}{T})^2$块(按照左端点所在块和右端点所在块分块),同块内按时间从小到大依次处理 ...

  9. HDU-1166 敌兵布阵 (树状数组模板题——单点更新,区间求和)

    题目链接 AC代码: #include<iostream> #include<cstdio> #include<cstring> #include<algor ...

随机推荐

  1. windows 下 基于express搭建 https协议的网站

    参考 https://blog.csdn.net/xingyanchao/article/details/79362443 问题在于生成SSL证书的时候Windows环境下会报错 解决方案 参考 ht ...

  2. process.env

    官方: process.env属性返回一个包含用户环境信息的对象.

  3. SpringMVC之请求响应(上)

    1.OutPutController package com.tz.controller; import java.util.Map; import org.springframework.stere ...

  4. Promise 的含义

    Promise 的含义 Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大.它由社区最早提出和实现,ES6 将其写进了语言标准,统一了用法,原生提供了Pro ...

  5. MySQL增、删、改、查基础操作(C++)

    系统平台:Centos7 MySQL版本:5.7.19 连接MySQL数据库 MySQL::MySQL(string host, string user, string passwd, string ...

  6. array, matrix, list and dataframe

    总结一下"入门3R"(Reading, 'Riting, 'Rrithmetic)中的读和写,不同的数据结构下的读写还是有点区别的. vector 命名 12 month.days ...

  7. idea激活教程(永久)支持2019 3.1 亲测

    此教程已支持最新2019.3版本 本教程适用Windows.Mac.Ubuntu等所有平台. 激活前准备工作 配置文件修改已经不在bin目录下直接修改,而是通过Idea修改 如果输入code一直弹出来 ...

  8. IP 转发分组的流程

    IP 转发分组的流程 数据路由:路由器在不同网段转发数据包: 网络畅通的条件:数据包能去能回: 从源网络发出时,沿途的每一个路由器必须知道到目标网络下一跳给哪个接口: 从目标网络返回时,沿途的每一个路 ...

  9. 如何在windows server上安装 Windows评估和部署工具包

    此文是<.NET内存宝典>一书的售后服务系列文章之一. 在<.NET内存宝典>一书(目前我还在翻译本书,预计年底出版)的第3章 “内存测量”里的“Windows性能工具包”一节 ...

  10. 7-19 计算有n个字符串中最长的字符串长度 (40 分)

    编写程序,用于计算有n(1<n<10)个字符串中最长的字符串的长度.前导空格不要计算在内! 输入格式: 在第一行中输入n,接下的每行输入一个字符串 输出格式: 在一行中输出最长的字符串的长 ...