bzoj 1901 有更新区间第k大 树状数组套可持久化线段树
来源:互联网 发布:49生男生女计算法准吗 编辑:程序博客网 时间:2024/04/30 16:01
http://www.lydsy.com/JudgeOnline/problem.php?id=1901
我的可持久化线段树消耗的内存太大了,在zoj超内存
如果对 上次的那题无修改的区间第k大的可持久化做法足够了解http://blog.csdn.net/haha593572013/article
那么稍微理解一下就能理解这道题了
在求区间第k大的时候,我们的本质其实是求出一棵包含且只包含所求区间信息的线段树,然后在整棵线段树中查询区间第k大的数,当然这棵线段树是通过做差得出来的,其实就是两个“前缀线段树”相减得出来的,即保存1~y区间信息的线段树 与 保存1~ x 区间信息的线段树节点信息相减,因为上题没有更新,所以每次直接从i-1时刻的线段树插入一个数得到i时刻的线段树,每次得到的新的线段树保存的信息都是1~ i 的信息,即都是前缀的信息
注意到了吗?前缀!!!那么如果有更新的操作的话,我们只需要维护好前缀的信息就可以了
具体做法是用树状数组来维护前缀(线段树)和,树状数组的每个节点又是一棵线段树,所以复杂度就要多乘一个log(n),即nlog^2(n)
求解x y区间第k大的数的时候还是一样,1到y的信息减去1到x-1的信息
具体的细节大家耐心研究下吧,蛮有意思的(树套树)
#include<cstdio>#include<algorithm>using namespace std;const int maxn = 120000;#define lson l,m,rt<<1#define rson m+1,r,rt<<1|1 int ls[maxn*20],rs[maxn*20],sum[maxn*20];int root[maxn],tot; void build(int l,int r,int &rt){ rt=++tot; sum[rt]=0; if(l==r) return ; int m=l+r>>1; build(l,m,ls[rt]); build(m+1,r,rs[rt]);}void update(int last,int p,int l,int r,int &rt,int v){ rt=++tot; ls[rt]=ls[last]; rs[rt]=rs[last];sum[rt]=sum[last]+v; if(l==r) return ; int m=l+r>>1; if(p <= m) update(ls[last],p,l,m,ls[rt],v); else update(rs[last],p,m+1,r,rs[rt],v);}int cc,n,m;int num[maxn];char op[10010][3];const int NN = 10010;int san[NN*2],P[NN],Q[NN],K[NN];int L[30],R[30];int N,M;int query(int l,int r,int k){ if(l==r) return l; int m=l+r>>1; int suma=0,sumb=0; for(int i=1;i<=N;i++) suma+=sum[ls[L[i]]]; for(int i=1;i<=M;i++) sumb+=sum[ls[R[i]]]; int del=sumb-suma; if(k <= del) { for(int i=1;i<=N;i++) L[i]=ls[L[i]]; for(int i=1;i<=M;i++) R[i]=ls[R[i]]; return query(l,m,k); } else { for(int i=1;i<=N;i++) L[i]=rs[L[i]]; for(int i=1;i<=M;i++) R[i]=rs[R[i]]; return query(m+1,r,k-del); }}int ask(int l,int r,int k){ N=0,M=0; for(;l>0;l-=l&-l) L[++N]=root[l]; for(;r>0;r-=r&-r) R[++M]=root[r]; return query(1,cc,k);}void Bit_update(int x,int val,int flag){ for(;x<=n;x+=x&-x) { update(root[x],val,1,cc,root[x],flag); }}int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { scanf("%d",&num[i]); san[++cc]=num[i]; } for(int i=1;i<=m;i++) { scanf("%s%d%d",op[i],&P[i],&Q[i]); if(op[i][0]=='Q'){ scanf("%d",&K[i]); } else san[++cc]=Q[i]; } sort(san+1,san+1+cc); cc=unique(san+1,san+1+cc)-san-1; for(int i=1;i<=n;i++) num[i]=lower_bound(san+1,san+1+cc,num[i])-san; build(1,cc,root[0]); for(int i=1;i<=n;i++) Bit_update(i,num[i],1); for(int i=1;i<=m;i++) { if(op[i][0]=='Q'){ int id=ask(P[i]-1,Q[i],K[i]); printf("%d\n",san[id]); } else { int pos=lower_bound(san+1,san+1+cc,Q[i]) - san; Bit_update(P[i],num[P[i]],-1); num[P[i]] = pos; Bit_update(P[i],num[P[i]],1); } } return 0;}
- bzoj 1901 有更新区间第k大 树状数组套可持久化线段树
- bzoj 1901 动态区间第K大 树状数组套可持久化数据结构
- 区间第k大 可修改主席树,树状数组套线段树。
- BZOJ 3110([Zjoi2013]K大数查询-区间第k大[段修改,在线]-树状数组套函数式线段树)
- 区间第k大(树状数组套值域线段树)
- [BZOJ 1901][ZOJ 2112]Dynamic Rankings(树状数组套主席树、动态区间第k大值查询)
- POJ2104-K-th Number-区间第k大-可持久化线段树/主席树
- POJ 2104 K-th Number 区间第K大,可持久化线段树
- hdu 5412 CRB and Queries(动态区间第k大值,区间能修改)(整体二分,树状数组套平衡树,线段树套treap)
- 可持久化线段树|主席树 POJ 2104 区间第k大的数
- 可持久化线段树(主席树)(图文并茂详解)【poj2104】【区间第k大】
- poj 2104 hdu 2665 区间第k大 可持久化线段树
- POJ 2104 可持久化线段树 求区间第k大
- 【可持久化线段树】poj 2104 静态区间第k大
- 可持久化线段树——Step 1 静态区间第K大
- 区间第K值(可持久化线段树)
- 区间第k小 poj2104 可持久化线段树
- 【bzoj 1901】树状数组套线段树
- XML——DTD约束应用、DTD约束语法细节
- xml约束
- elasticsearch学习入门
- 标准的软件工程过程之文档标准
- 一个fork的面试题
- bzoj 1901 有更新区间第k大 树状数组套可持久化线段树
- linux设备驱动——andriod平台wlan驱动
- padding与margin区别
- 14岁初中生—— 踏踏实实的人生也最美
- 软件工程中使用到的文档
- 唠唠叨叨又七夕
- 《机动车驾驶证申领和使用规定》(公安部令第123号)
- 从三巨头说云计算
- 第七周任务几忘了—两数之差