替罪羊树套线段树 【bzoj3065】 带插入区间k小值
来源:互联网 发布:阿里云服务器别名解析 编辑:程序博客网 时间:2024/05/16 19:51
题目大意:
维护一个序列。
支持以下操作:
1、查询区间k小值
2、修改一个值
3、插入一个值
题目分析:
如果不带插入,主席树就可以搞定了。
带插入的话我们就既要维护权值大小,又要维护位置,一维的数据结构无法同时维护这两个值,所以就采用树套树的方法。
内层用权值线段树维护权值,外层用平衡树来维护位置。
但是平衡树里存的节点信息是一大颗果实饱满充满生机富有活力的线段树,无法快速合并,怎么办?
那就不合并……
平衡树通过旋转来保证时间复杂度,有旋转就要有合并子树信息,怎么办?
那就不旋转……
于是我们学了替罪羊树。
替罪羊树的思想就是,如果某个节点出现了严重的不平衡现象(某一个儿子太大),严重影响其他操作的时间复杂度,那我们就暴力重建它。
也就是说替罪羊树除了把旋转改为暴力重建之外,其他与普通平衡树相同。
所以就外层替罪羊树,里层权值线段树。
查询要二分答案,时间复杂度log^3n
修改和插入都是log^2n
时间复杂度上界Omlog^3n
代码部分借鉴自PoPoQQQ
这道题需要写垃圾回收,Po神真的很腻(neng)害(zuo)呀,重载new和delete什么的……心好累=。=
代码如下:
#include <cstdio>#include <cstring>#include <iostream>#include <queue>#define M 70700#define MAXN 70000#define ALPHA 0.8using namespace std;struct segment{ segment *ls,*rs; int num; void* operator new(size_t size); void operator delete(void *p); void Insert(int l,int r,int x); void Delete(int l,int r,int x); int Query(int l,int r,int x); void Decomposition();}*C,*mempool;struct sheep{ sheep *ls,*rs; int num,sz; segment *tree; void* operator new(size_t size,int x); void operator delete(void *p); void maintain(); void Decomposition(); bool check();}*G,*_mempool,*root;int n,m,x,y,k,tot,top,ans,a[M];char s[10];queue<void*> bin_seg,bin_sheep;sheep **sta[M];void* segment :: operator new(size_t size){ if(!bin_seg.empty()) { void *re=bin_seg.front(); bin_seg.pop(); memset(re,0,sizeof(segment)); return re; } if(C==mempool) { C=new segment[1<<15]; mempool=C+(1<<15); memset(C,0,sizeof(segment)*(1<<15)); } return C++;}void segment :: operator delete(void *p){ bin_seg.push(p);}void segment :: Insert(int l,int r,int x){ num++; if(l==r) return; int mid=l+r>>1; if(x<=mid) { if(!ls) ls=new segment; ls->Insert(l,mid,x); } else { if(!rs) rs=new segment; rs->Insert(mid+1,r,x); }}void segment :: Delete(int l,int r,int x){ num--; if(l==r) return; int mid=l+r>>1; if(x<=mid) ls->Delete(l,mid,x); else rs->Delete(mid+1,r,x);}int segment :: Query(int l,int r,int x){ int mid=l+r>>1; if(!num) return 0; if(l==r) return num; if(x<=mid) return ls?ls->Query(l,mid,x):0; return (ls?ls->num:0)+(rs?rs->Query(mid+1,r,x):0);}void segment :: Decomposition(){ if(ls) ls->Decomposition(); if(rs) rs->Decomposition(); delete this;}void* sheep :: operator new (size_t size,int x){ if(!bin_sheep.empty()) { sheep *re=(sheep*)bin_sheep.front(); bin_sheep.pop(); re->ls=re->rs=0x0; re->num=x; re->sz=1; re->tree=new segment; return re; } if(G==_mempool) { G=new sheep[1<<15]; _mempool=G+(1<<15); memset(G,0,sizeof(sheep)*(1<<15)); } G->ls=G->rs=0x0; G->num=x; G->sz=1; G->tree=new segment; return G++;}void sheep :: operator delete(void *p){ bin_sheep.push(p);}void sheep :: maintain(){ sz=1; if(ls) sz+=ls->sz; if(rs) sz+=rs->sz;}void sheep :: Decomposition(){ if(ls) ls->Decomposition(); a[++tot]=num; if(rs) rs->Decomposition(); tree->Decomposition(); delete this;}bool sheep :: check(){ if(ls) { double rate=ls->sz*1.0/sz; if(rate>ALPHA) return true; } if(rs) { double rate=rs->sz*1.0/sz; if(rate>ALPHA) return true; } return false;}int query(sheep *c,int x,int k){ if(x<=0) return 0; int tmp=c->ls?c->ls->sz:0,re=0; if(x<=tmp) return query(c->ls,x,k); x-=tmp; if(c->ls) re+=c->ls->tree->Query(0,MAXN,k); x--; re+=(c->num<=k); if(!x) return re; return re+query(c->rs,x,k);}int query(int x,int y,int k){ int l=0,r=MAXN; int ans=0; while(l<=r) { int mid=l+r>>1; if(query(root,y,mid)-query(root,x-1,mid)>=k) ans=mid,r=mid-1; else l=mid+1; } return ans;}void modify(sheep *c,int x,int val){ static int change; int tmp=c->ls?c->ls->sz:0; if(x<=tmp) modify(c->ls,x,val); else if((x-=tmp)==1) change=c->num,c->num=val; else modify(c->rs,--x,val); c->tree->Insert(0,MAXN,val); c->tree->Delete(0,MAXN,change);}sheep* build_tree(int l,int r){ if(l>r) return 0x0; int mid=l+r>>1; sheep *re=new (a[mid]) sheep; re->ls=build_tree(l,mid-1); re->rs=build_tree(mid+1,r); for(int i=l;i<=r;i++) re->tree->Insert(0,MAXN,a[i]); re->maintain(); return re;}void rebuild(sheep *&c){ top=tot=0; c->Decomposition(); c=build_tree(1,tot);}void insert(sheep *&c,int x,int val){ if(!c) { c=new (val) sheep; c->tree->Insert(0,MAXN,val); return; } c->tree->Insert(0,MAXN,val); int tmp=c->ls?c->ls->sz:0; if(x<=tmp) { insert(c->ls,x,val); if(c->ls->check()) sta[++top]=&c->ls; } else { insert(c->rs,x-tmp-1,val); if(c->rs->check()) sta[++top]=&c->rs; } c->maintain();}void insert(int x,int val){ --x,++n; insert(root,x,val); if(root->check()) sta[++top]=&root; if(top) rebuild(*sta[top]);}int main(){ scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]); root=build_tree(1,n); scanf("%d",&m); for(int i=1;i<=m;i++) { scanf("%s%d%d",s,&x,&y); x^=ans;y^=ans; switch(s[0]) { case 'Q': scanf("%d",&k);k^=ans; printf("%d\n",ans=query(x,y,k)); break; case 'M': modify(root,x,y); break; case 'I': insert(x,y); break; } } return 0;}
0 0
- 替罪羊树套线段树 【bzoj3065】 带插入区间k小值
- [bzoj3065]带插入区间K小值 替罪羊树套值域线段树
- BZOJ3065: 带插入区间K小值(替罪羊树+权值线段树)
- BZOJ 3065 带插入区间K小值 替罪羊树套线段树
- BZOJ 3065 带插入区间K小值 替罪羊树套线段树
- bzoj 3065: 带插入区间K小值 替罪羊树套线段树
- [分块 块的分裂 || 替罪羊树套线段树] BZOJ 3065 带插入区间K小值
- bzoj 3065: 带插入区间K小值 替罪羊树套主席树
- BZOJ3065 带插入区间K小值
- [bzoj3065]带插入区间K小值
- bzoj3065带插入区间K小值
- BZOJ3065 带插入区间K小值
- bzoj3065: 带插入区间K小值
- 【BZOJ3065】带插入区间K小值
- BZOJ 3065: 带插入区间K小值 替罪羊树套权值线段树 详解
- [bzoj3065]带插入区间K小值 解题报告
- bzoj 3065 带插入区间K小值 重量平衡treap套主席树
- BZOJ 2141 排队 线段树套替罪羊
- HTML基础 HTML重点知识总结
- HaDoop:WARN util.NativeCodeLoader解决办法
- BootStrap 表单
- tabSwitch 选项卡
- Mac快捷键及Android studio for mac快捷键
- 替罪羊树套线段树 【bzoj3065】 带插入区间k小值
- Android RecyclerView加载时大图卡顿
- Flume-ng源码解析之Source组件
- 开源alisql压测批处理性能
- Android UI的有关使用
- Android Studio 升级2.3以后无法启动App的解决方案
- Telecom指令源码
- mmap
- Mac安装homebrew