zoj 2112 单点修改的主席树(树状数组套主席树)
题目大意:
区间第k大问题+单点修改
基本思路:
这个题有用整体二分,cdq分治,还有主席树+平衡树的,还有就是主席树+树状数组。
我采用的是b站电子科大大佬的主席树写法,尤其喜欢他的离散化方法,所以就这么写了。
下面对代码进行下解释(当然,详细解释看注解):
root[i]:第i棵树根节点的编号,i就是原来序列的下标,代码里从1开始
tr[i]:树状数组第i棵树根节点的编号
ur[i],ul[i]:临时用来存从第i棵树根节点编号到左右子树编号一直到底。
-----------------------------------------------------------------------------
详细注解,转自:https://blog.csdn.net/WilliamSun0122/article/details/77885781
其实静态主席树我们弄清楚之后,动态的可以很快学会。因为动态主席树就是在静态主席树的基础上增加了一批用树状数组思维维护的线段树。
我们以下面的例子讲解。
5 3
3 2 1 4 7
Q 1 4 3 询问区间[1,4]第3小数
C 2 6 把第2个数变为6
Q 2 5 3 询问区间[2,5]第3小数
n是原序列个数
T[i]表示第i棵线段树的根节点编号
S[i]表示树状数组思维建的第i棵线段树的根节点编号
L[i]表示节点i的左子节点编号
R[i]表示节点i的右子节点编号
sum[i]表示节点i对应区间中数的个数。
这里离散化建树过程和静态主席树有一点不同,我们必须把所有询问先存起来并且把改变的数也加入到原序列中再离散化建树,会导致空间复杂度和静态有所区别(之前讲静态的时候提过)。所以这里我们离散化后序列为3 2 1 4 6 5分别对应原序列的3 2 1 4 7和改变后的6。
之后同静态一样建空树,按原序列前缀建树,相信不用我说了。(画图有点麻烦,我借鉴参考博客的图,这个图是没错的)

接下来就是重点了,对于题目给出的修改操作,我们新建一批线段树来记录更新,这些线段树以树状数组的思维来维护。
一开始,S[0]、S[1]、S[2]、S[3]、S[4]、S[5] (注意一共有n+1个 即 0到n)(树状数组的每个节点)这些都与T[0]相同(也就是每个节点建了一棵空树)。
对于C 2 6 这个操作, 我们只需要减去一个2,加上一个5(对应改变后的6)即可。
这个更新我们按树状数组的思想更新,比如这里的减2,我们要从i=2(原序列中第2个数2在离散化后序列中的位置)即S[2]开始更新,并往上lowbit(i)直到大于5,这里我们会更新S[2]和S[4]。
边看图边理解(这个图最后应该是在节点5那里减1)

对于加5同样是从S[2]开始更新
(这个图最后应该是在节点10那里加1) 
这样我们查询的时候T[]和静态一样,再按树状数组的思维加上S[]就可算出每个节点对应区间中数的个数,再按静态的思想查询即可。
对于原序列n个数,m次询问
空间复杂度(我的理解)
因为这里我们要加入询问中数离散化后再建树,所以建树4*(n+m)
按原序列更新T[],nlog2(n+m)log2(n+m)
每次询问更新S[],2log2nlog2n(按树状数组最多更新的节点)log2(n+m)log2(n+m)(每次最多更新线段树中的节点)
加起来即可,不过你真这么开数组的话肯定会MLE。
以zoj2112为例,参考博客开的范围是2*(n+m)log2(n+m)log2(n+m)(大概,我是强行解释,我范围开大会Segmentation fault,开小会RE)
我猜大概是因为如果每次询问都是修改操作的话按静态中的开应该会是(n+m)log2(n+m)log2(n+m)还要加上一个S[],所以要*2。
时间复杂度(我的理解)
mlog2nlog2nlog2(n+m)
代码如下:
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int inf = 0x3f3f3f3f;
const int maxn = 60000+10;
int n,q,num,cnt;
int root[maxn],tr[maxn],arr[maxn],ul[maxn],ur[maxn];
vector<int>vec;
struct Node{
int l,r,sum;
}T[maxn*32];
struct Ques{
bool flag;
int l,r,k;
}ques[maxn];
int getid(int x){
return lower_bound(vec.begin(),vec.end(),x)-vec.begin()+1;
}
void update(int l,int r,int& x,int y,int pos,int val){
T[++cnt]=T[y];
T[cnt].sum+=val;
x=cnt;
if(l==r){
return;
}
int mid=(l+r)/2;
if(pos<=mid){
update(l,mid,T[x].l,T[y].l,pos,val);
}else{
update(mid+1,r,T[x].r,T[y].r,pos,val);
}
}
int lowbit(int x){
return x&(-x);
}
void add(int x,int val){
int ans=getid(arr[x]);
while(x<=n){
update(1,num,tr[x],tr[x],ans,val);
x+=lowbit(x);
}
}
int getSum(int x,bool flag){
int ans=0;
while(x>0){
if(flag){
ans+=T[T[ur[x]].l].sum;
}else{
ans+=T[T[ul[x]].l].sum;
}
x-=lowbit(x);
}
return ans;
}
int query(int l,int r,int s,int e,int ts,int te,int k){
if(l==r){
return l;
}
int mid=(l+r)/2;
int ans=getSum(e,true)-getSum(s,false)+T[T[te].l].sum-T[T[ts].l].sum;
if(k<=ans){
//从根节点每次将相关所有节点下降一层
for(int i=e;i;i-=lowbit(i)){
ur[i]=T[ur[i]].l;
}
for(int i=s;i;i-=lowbit(i)){
ul[i]=T[ul[i]].l;
}
return query(l,mid,s,e,T[ts].l,T[te].l,k);
}else{
for(int i=e;i;i-=lowbit(i)){
ur[i]=T[ur[i]].r;
}
for(int i=s;i;i-=lowbit(i)){
ul[i]=T[ul[i]].r;
}
return query(mid+1,r,s,e,T[ts].r,T[te].r,k-ans);
}
}
int main(){
int cas;
scanf("%d",&cas);
while(cas--){
cnt=0;
vec.clear();
scanf("%d%d",&n,&q);
for(int i=1;i<=n;i++){
scanf("%d",&arr[i]);
vec.push_back(arr[i]);
}
char op[5];
for(int i=1;i<=q;i++){
scanf("%s",op);
if(op[0]=='Q'){
ques[i].flag=false;
scanf("%d%d%d",&ques[i].l,&ques[i].r,&ques[i].k);
}else{
ques[i].flag=true;
scanf("%d%d",&ques[i].l,&ques[i].r);
vec.push_back(ques[i].r);
}
}
//离散化
sort(vec.begin(),vec.end());
vec.erase(unique(vec.begin(),vec.end()),vec.end());
num=vec.size();
for(int i=1;i<=n;i++){
update(1,num,root[i],root[i-1],getid(arr[i]),1);
}
for(int i=1;i<=n;i++){
tr[i]=root[0];
}
for(int i=1;i<=q;i++){
if(ques[i].flag){
add(ques[i].l,-1);
arr[ques[i].l]=ques[i].r;
add(ques[i].l,1);
}else{
for(int j=ques[i].r;j;j-=lowbit(j)){
ur[j]=tr[j];
}
for(int j=ques[i].l-1;j;j-=lowbit(j)){
ul[j]=tr[j];
}
printf("%d\n",vec[query(1,num,ques[i].l-1,ques[i].r,root[ques[i].l-1],root[ques[i].r],ques[i].k)-1]);
}
}
}
}
zoj 2112 单点修改的主席树(树状数组套主席树)的更多相关文章
- ZOJ 2112 Dynamic Rankings(树状数组套主席树 可修改区间第k小)题解
题意:求区间第k小,节点可修改 思路:如果直接用静态第k小去做,显然我更改一个节点后,后面的树都要改,这个复杂度太高.那么我们想到树状数组思路,树状数组是求前缀和,那么我们可以用树状数组套主席树,求出 ...
- BZOJ2120:数颜色(数状数组套主席树)(带修改的莫对)
墨墨购买了一套N支彩色画笔(其中有些颜色可能相同),摆成一排,你需要回答墨墨的提问.墨墨会像你发布如下指令: 1. Q L R代表询问你从第L支画笔到第R支画笔中共有几种不同颜色的画笔. 2. R P ...
- BZOJ 3196 Tyvj 1730 二逼平衡树 ——树状数组套主席树
[题目分析] 听说是树套树.(雾) 怒写树状数组套主席树,然后就Rank1了.23333 单点修改,区间查询+k大数查询=树状数组套主席树. [代码] #include <cstdio> ...
- P2617 Dynamic Rankings(树状数组套主席树)
P2617 Dynamic Rankings 单点修改,区间查询第k大 当然是无脑树套树了~ 树状数组套主席树就好辣 #include<iostream> #include<cstd ...
- [bzoj3196][Tyvj1730]二逼平衡树_树套树_位置线段树套非旋转Treap/树状数组套主席树/权值线段树套位置线段树
二逼平衡树 bzoj-3196 Tyvj-1730 题目大意:请写出一个维护序列的数据结构支持:查询给定权值排名:查询区间k小值:单点修改:查询区间内定值前驱:查询区间内定值后继. 注释:$1\le ...
- bzoj1901--树状数组套主席树
树状数组套主席树模板题... 题目大意: 给定一个含有n个数的序列a[1],a[2],a[3]--a[n],程序必须回答这样的询问:对于给定的i,j,k,在a[i],a[i+1],a[i+2]--a[ ...
- BZOJ 1901 Zju2112 Dynamic Rankings ——树状数组套主席树
[题目分析] BZOJ这个题目抄的挺霸气. 主席树是第一时间想到的,但是修改又很麻烦. 看了别人的题解,原来还是可以用均摊的思想,用树状数组套主席树. 学到了新的姿势,2333o(* ̄▽ ̄*)ブ [代 ...
- BZOJ1901 - Dynamic Rankings(树状数组套主席树)
题目大意 给定一个有N个数字的序列,然后又m个指令,指令种类只有两种,形式如下: Q l r k 要求你查询区间[l,r]第k小的数是哪个 C i t 要求你把第i个数修改为t 题解 动态的区间第k ...
- BZOJ_3196_Tyvj 1730 二逼平衡树_树状数组套主席树
BZOJ_3196_Tyvj 1730 二逼平衡树_树状数组套主席树 Description 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作: 1.查询k在区间内的排 ...
- [COGS257]动态排名系统 树状数组套主席树
257. 动态排名系统 时间限制:5 s 内存限制:512 MB [问题描述]给定一个长度为N的已知序列A[i](1<=i<=N),要求维护这个序列,能够支持以下两种操作:1.查询A[ ...
随机推荐
- BZOJ3625 CF438E 小朋友与二叉树
心态崩了 不放传送门了 辣鸡bz 还是正经一点写一下题解= = 就是显然我们可以把权值写成生成函数形式g(0/1序列)来表示权值是否出现 然后f来表示总的方案数 可以列出 分别枚举左右子树和空树的情况 ...
- 7.搭建hyperledger fabric环境及启动——2019年12月12日
2019年12月12日13:05:16 声明:从网络中学习整理实践而来. 1.介绍fabric Fabric 是一个面向企业应用的区块链框架,基于 Fabric 的开发可以粗略分为几个层面: 1. 参 ...
- 零基础python教程-Python解释器是什么?
当我们编写Python代码时,我们得到的是一个包含Python代码的以.py为扩展名的文本文件.要运行代码,就需要Python解释器去执行.py文件. 由于整个Python语言从规范到解释器都是开源的 ...
- git 切换分支开发并合并提交到远程仓库
- shell脚本学习(3)sed替换
1 sed 替换 1格式: 's/原字符串/新字符串/' 输入源 2正确参考: sed ’s/as/AS/' do.txt 改变字符串as为AS,不会改输入源的文件. 匹配每行第一次匹配的 ...
- 2019 牛客暑期多校 第八场 A All-one Matrices (单调栈+前缀和)
题目:https://ac.nowcoder.com/acm/contest/888/A 题意:找全1矩阵的个数,并且这个全1矩阵不被其他全1矩阵包含 思路:这里引用付队说的话 -> { 这类问 ...
- UILabel How to set background image
UILabel *myLabel=[[UILabel alloc] initWithFrame:CGRectMake(0, 0, 320, 20)]; UIImage *img = [UIImage ...
- JS继承 实现方式
JS中继承方式的实现有多种方法,下面是比较推荐的方法,其它继承方式可做了解: function object(o) { function F() {} F.prototype = o; return ...
- python中模块介绍
一,模块概念 在计算机程序开发的过程当中,随着程序代码越写越多,在一个文件里代码就会越来越长,越来越不容易维护.为了编码更加容易维护,我们把很多函数分组,分别放到不同的文件里,这样,每个文件包含的代码 ...
- 杂项-报表-Minitab:Minitab百科
ylbtech-杂项-报表-Minitab:Minitab百科 Minitab软件是现代质量管理统计的领先者,全球六西格玛实施的共同语言,以无可比拟的强大功能和简易的可视化操作深受广大质量学者和统计专 ...