总算是把动态求区间第k个数的算法看明白了。
在主席树的基础上,如果有修改操作,则要通过套树状数组来实现任意区间求第k小的问题。
刚开始看不明白什么意思,现在有一点理解。树状数组的每个元素是一个线段树,来维护修改后的前后缀和,树状数组能在log时间内更整个数组,现在用相同的方式更新整个线段树数组,每次更新一个点时,要更新这个点代表的整个线段树。同样的,求和时用一个use数组记录所要更新的点的下标,每次求不同线段树的同一位置的和。
静态初值不要用来初始化树状数组。
考虑到前缀和,我们通过树状数组来优化,即树状数组套主席树,每个节点都对应一棵主席树,那么修改操作就只要修改logn棵树,
O(nlognlogn+Mlognlogn)时间是可以的,但是直接建树要nlogn*logn(10^7)会MLE。

我们发现对于静态的建树我们只要nlogn个节点就可以了,而且对于修改操作,只是修改M次,每次改变俩个值(减去原先的,加上现

在的)也就是说如果把所有初值都插入到树状数组里是不值得的,所以我们分两部分来做,所有初值按照静态来建,内存O(nlogn),

而修改部分保存在树状数组中,每次修改logn棵树,每次插入增加logn个节点O(M*logn*logn+nlogn)。
离线处理
傻逼题 一直 SF
问题听说 是一定要初始化= =不知都为啥。。傻逼题。。我的代码2 可能在 bzoj 能过。。不清楚。。因为他挂了 代码1是能过的,拿来做板子吧

代码1的方法就是 先建一棵完整的树,就像初始化一样,代码2是直接插入,这样就是树一开始会不一样,代码2默认全部为0,代码1默认一开始的一棵树为0,然后开始改变
代码1:

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;
typedef long long ll;
const int maxn = 5e4+10;
int n,m,tot,idx;
ll a[maxn],vec[maxn*2];
struct
{int x,y,k,flag,idx;
} Q[maxn];//   主席树
int lson[maxn*50],rson[maxn*50],c[maxn*50],root[maxn]; //依次为左儿子 右儿子 sum  根节点
int build (int l,int r)
{int root = tot++;c[root] = 0;if (l != r){int mid = (l + r) >> 1;lson[root] = build(l,mid);rson[root] = build(mid+1,r);}return root;
}
int update(int root,int pos,int val)
{int new_root = tot++;int tmp = new_root;int l = 1,r = idx;c[new_root] = c[root] + val;while (l < r) //用二分而不是递归 减少内存占用 递归可能爆栈{int mid = (l + r) >> 1;if (pos <= mid){rson[new_root] = rson[root];// 把旧的右结点赋值到新的右结点root = lson[root];// 当前的左结点成为新的旧结点lson[new_root] = tot++;// 创建新的左结点new_root = lson[new_root];r = mid;}else{lson[new_root] = lson[root];root = rson[root];rson[new_root] = tot++;new_root = rson[new_root];l = mid + 1;}c[new_root] = c[root] + val;// root 是旧的 new是新的 用旧的更新新的}return tmp;
}
//  树状数组维护
int s[maxn],use[maxn];
inline int lowbit (int x)
{return x & -x;
}
void add(int k,int pos,int d)
{while (k <= n){s[k] = update(s[k],pos,d);k += lowbit(k);}
}
int sum(int pos)
{int res = 0;while (pos){res += c[lson[use[pos]]];pos -= lowbit(pos);}return res;
}
int query(int left,int right,int k)
{int l_root = root[left-1];int r_root = root[right];for (int i = left-1; i > 0; i -= lowbit(i))use[i] = s[i];for (int i = right; i > 0; i -= lowbit(i))use[i] =s[i];int l = 1,r = idx;while (l < r)//用二分而不是递归 减少内存占用 递归可能爆栈{int t = sum(right) - sum(left-1) + c[lson[r_root]] - c[lson[l_root]];int mid = (l + r) >> 1;if (t >= k){for (int i = left-1; i > 0; i -= lowbit(i))use[i] = lson[use[i]];for (int i = right; i > 0; i -= lowbit(i))use[i] = lson[use[i]];l_root = lson[l_root];r_root = lson[r_root];r = mid;}else{for (int i = left-1; i > 0; i -= lowbit(i))use[i] = rson[use[i]];for (int i = right; i > 0; i -= lowbit(i))use[i] = rson[use[i]];l_root = rson[l_root];r_root = rson[r_root];k -= t;l = mid + 1;}}return l;
}void read()
{scanf ("%d%d",&n,&m);for (int i = 1; i <= n; i++){scanf ("%lld",a+i);vec[++idx] = a[i];}for (int i = 0; i < m; i++){char op[3];scanf ("%s",op);if (op[0] == 'C'){scanf ("%d%d",&Q[i].x,&Q[i].y);Q[i].flag = 0;vec[++idx] = Q[i].y;}if (op[0] == 'Q'){scanf ("%d%d%d",&Q[i].x,&Q[i].y,&Q[i].k);Q[i].flag = 1;}}
}
int main(void)
{int T;scanf ("%d",&T);while (T--){idx = tot = 0;read();sort(vec,vec+idx);                   //离散化idx = unique(vec,vec+idx) - vec;root[0] = build(1,idx);for (int i = 1; i <= n; i++){int tmp = lower_bound(vec+1,vec+idx+1,a[i]) - vec ;root[i] = update(root[i-1],tmp,1);}for (int i = 0; i <= n; i++)s[i] = root[0];for (int i = 0; i < m; i++){if (Q[i].flag == 0){int tmp1 = lower_bound(vec+1,vec+idx+1,a[Q[i].x]) - vec ;int tmp2 = lower_bound(vec+1,vec+idx+1,Q[i].y) - vec ;add(Q[i].x,tmp1,-1);add(Q[i].x,tmp2,1);a[Q[i].x] = Q[i].y;}if (Q[i].flag == 1){printf("%lld\n",vec[query(Q[i].x,Q[i].y,Q[i].k)]);}}}return 0;
}

代码2:

#include <bits/stdc++.h>
using namespace std;
const int N = 50500;
#define lowbit(x) (x)&(-x)
int ls[N*40],rs[N*40],sum[N*40];
int v[3*N],has[3*N],tmp[3*N];
int tot,root[3*N];
int sze,a,b;//sze代表总的节点数
int LS[3*N],RS[3*N];
struct Q
{int flag,l,r,k;int d,x;
}q[N];void update(int l,int r,int pre,int &now,int d,int val)
{now=++sze;ls[now]=ls[pre];rs[now]=ls[pre];sum[now]=sum[pre]+val;if(l==r) return ;int mid=(l+r)>>1;if(d<=mid) update(l,mid,ls[pre],ls[now],d,val);else update(mid+1,r,rs[pre],rs[now],d,val);
}int query(int l,int r,int k)
{if(l==r) return l;int suml=0,sumr=0;for(int i=0;i<a;i++) suml+=sum[ls[LS[i]]];for(int i=0;i<b;i++) sumr+=sum[ls[RS[i]]];int mid=(l+r)>>1;if((sumr-suml)>=k){for(int i=0;i<a;i++) LS[i]=ls[LS[i]];for(int i=0;i<b;i++) RS[i]=ls[RS[i]];return query(l,mid,k);}else {for(int i=0;i<a;i++) LS[i]=rs[LS[i]];for(int i=0;i<b;i++) RS[i]=rs[RS[i]];return query(mid+1,r,k-(sumr-suml));}}int main()
{int t;scanf("%d",&t);while(t--){sze=0;tot=0;a=0,b=0;memset(sum,0,sizeof(sum));int n,m;scanf("%d%d",&n,&m);for(int i=1;i<=n;i++){scanf("%d",&v[i]);tmp[++tot]=v[i]; //tot指数的总个数}char ch;for(int i=1;i<=m;i++){scanf(" %c",&ch);if(ch=='Q'){q[i].flag=1;scanf("%d%d%d",&q[i].l,&q[i].r,&q[i].k);}else{scanf("%d%d",&q[i].d,&q[i].x);tmp[++tot]=q[i].x;}}sort(tmp+1,tmp+tot+1);tmp[0]=-1;int cnt=0;// 数的种类for(int i=1;i<=tot;i++){if(tmp[i]!=tmp[i-1]) has[++cnt]=tmp[i];}for(int i=1;i<=n;i++){int tt=lower_bound(tmp+1,tmp+tot+1,v[i])-tmp;for(int j=i;j<=n;j+=lowbit(j))update(1,cnt,root[j],root[j],tt,1);}for(int i=1;i<=m;i++){if(q[i].flag==1){a=0,b=0;for(int j=q[i].l-1;j>0;j-=lowbit(j))LS[a++]=root[j];for(int j=q[i].r;j>0;j-=lowbit(j))RS[b++]=root[j];printf("%d\n",has[query(1,cnt,q[i].k)] );}else{int tt=lower_bound(tmp+1,tmp+tot+1,v[q[i].d])-tmp;for(int j=q[i].d;j<=n;j+=lowbit(j))update(1,cnt,root[j],root[j],tt,-1);v[q[i].d]=q[i].x;int tt1=lower_bound(tmp+1,tmp+tot+1,q[i].x)-tmp;for(int j=q[i].d;j<=n;j+=lowbit(j))update(1,cnt,root[j],root[j],tt1,1);}}}
}

转载于:https://www.cnblogs.com/dabai520/p/7554185.html

zoj 2112 树状数组 套主席树 动态求区间 第k个数相关推荐

  1. H - Hello Ms. Ze(树状数组套主席树,线段树上二分)

    H - Hello Ms. Ze 给定nnn种不同的材料,第iii种材料有aia_iai​个,有mmm个操作,操作分为两类: 把第xxx种材料修改为yyy个, 只用[l,r][l, r][l,r]区间 ...

  2. ICPC 徐州 H Yuuki and a problem (树状数组套主席树)

    Yuuki and a problem 先不管第一问的修改操作,考虑如何达到第二问的查询操作, 题目要我们给出一个区间[l,r][l, r][l,r]中,不能通过权值+++得到的最小的数字是什么, 假 ...

  3. #279. [SYZOI Round1] 滑稽♂树(树状数组套主席树)

    #279. [SYZOI Round1] 滑稽♂树 子树上的问题,考虑dfsdfsdfs序,第kkk大,可以用主席树嘛,支持修改,那就树状数组上套主席树,参考P4175 [CTSC2008]网络管理( ...

  4. 【BZOJ1901】Dynamic Rankings,树状数组套主席树

    Time:2016.05.09 Author:xiaoyimi 转载注明出处谢谢 传送门(权限) 题面 1901: Zju2112 Dynamic Rankings Time Limit: 10 Se ...

  5. 【BZOJ】1901: Zju2112 Dynamic Rankings(区间第k小+树状数组套主席树)

    http://www.lydsy.com/JudgeOnline/problem.php?id=1901 首先还是吐槽时间,我在zoj交无限tle啊!!!!!!!!我一直以为是程序错了啊啊啊啊啊啊. ...

  6. BZOJ1146[CTSC2008]网络管理——出栈入栈序+树状数组套主席树

    题目描述 M公司是一个非常庞大的跨国公司,在许多国家都设有它的下属分支机构或部门.为了让分布在世界各地的N个 部门之间协同工作,公司搭建了一个连接整个公司的通信网络.该网络的结构由N个路由器和N-1条 ...

  7. BZOJ1901Zju2112 Dynamic Rankings——树状数组套主席树

    题目描述 给定一个含有n个数的序列a[1],a[2],a[3]--a[n],程序必须回答这样的询问:对于给定的i,j,k,在a[i],a[i+1 ],a[i+2]--a[j]中第k小的数是多少(1≤k ...

  8. 洛谷 - P2617 Dynamic Rankings(树状数组套主席树)

    题目链接:点击查看 题目大意:给出一个长度为 n 的数列 a,再给出 m 次操作: Q l r k:返回区间 [ l , r ] 内第 k 大的数 C x y:令 a[ x ] = y 题目分析:其实 ...

  9. BZOJ1901 Zju2112 Dynamic Rankings 【树状数组套主席树】

    题目 给定一个含有n个数的序列a[1],a[2],a[3]--a[n],程序必须回答这样的询问:对于给定的i,j,k,在a[i],a[i+1],a[i+2]--a[j]中第k小的数是多少(1≤k≤j- ...

最新文章

  1. S.O.L.I.D.类设计原则
  2. 面向切面编程-日志切面应用
  3. extremeComponents(ec)源码分析
  4. windows下文件共享以及通过网线在两台Windows电脑之间传数据
  5. Spark基础脚本入门实践2:基础开发
  6. apache poi使用例_GitHub - cooker/poi-examples: apache poi 使用案例
  7. LeetCode题集大全
  8. C程序员要学C++吗?
  9. keyCode键码值对照表
  10. win10+Vmware14+Centeros7.6 mini网络设置
  11. 关于MySQL的存储函数(自定义函数)的定义和使用方法详解
  12. Word2Vec算法详解(相关背景介绍)
  13. jsp 如何上传文件到服务器上,如何使用JSP / Servlet将文件上传到服务器?
  14. 利用Apply的参数数组化来提高代码的优雅性,及高效性
  15. 数据分析之pandas-profiling
  16. Android获取用户通讯录上传,Android获取通讯录并上传(包含通讯录加密)(示例代码)...
  17. JDK命令一、javah命令(C Header and Stub File Generator)
  18. 基于 RK3399 5G 通信和图像增强算法的交通监控系统设计
  19. 递归算法php,PHP递归算法(二)
  20. 昨天,终于拿到了腾讯 offer

热门文章

  1. 买g 怀旧 被封号_防火防盗防封号 《魔兽世界》怀旧服自救指南
  2. python网页提交表单_使用Python中的POST请求通过网站表单上传基本文件
  3. Integer转BigDecimal
  4. 罗马仕php30重量,充电宝多少毫安最好?这3款罗马仕充电宝必须收藏
  5. .class与.java_Java中Class类的作用与深入理解
  6. 位运算的简单应用,计算无符号的数中二进制位中值为 1 的个数
  7. 我的 2018 年终总结
  8. 关于CSS HACK
  9. WinForm程序启动时不显示主窗体的实现方法
  10. 《人机交互与戏剧表演:用戏剧理论构建良好用户体验》一导读