bzoj 3065 带插入区间K小值 重量平衡treap套主席树
2016-08-29 20:05
316 查看
题意:维护一个数列,支持插入,修改,查询区间k小值。
我数据结构还是太弱呀QAQ
看了myy的课件和vfk的题解
treap支持重量平衡,也就是他插入删除影响的节点数都是O(log) 的。
先说插入,我们先把点插入到最下面,然后往上旋,假设这个点转到祖先k的位置,那么影响节点为sizek 个,由于这个点的随机权值是sizek 个点中最小的,这个的概率是1sizek 的。期望是O(1),一个点有O(log) 个祖先,因此总期望影响节点数O(log)
对于删除,由于treap形态是由随机权值决定的,因此删除的数在treap上位置是随机的。由于treap中一个点的子树的期望大小是O(log) 的。因此是O(log) 的。
treap插入一个元素旋转的期望次数是O(1) 的。因为他的随机权值必须比上面的随机权值大才会旋转,这个次数期望O(1)
前面是几个保证复杂度的东西。
treap每个点代表一个数列中的点。每个点开一棵权值线段树维护子树中的所有点的权值。
由于旋转次数期望O(1),因此可以每次旋转之后直接更新一下信息,不需要最后重构子树里的线段树。
旋转x时,设y是x的父亲,那么旋转后x的线段树和旋转前y的线段树相同,只需更新一下y的线段树。
一开始想用O(log) 的线段树合并,不过线段树合并不支持内存回收,可能MLE,因此写了一个合并到底的O(log2) 。
查询时用前缀和相减的方法,可以得到log 个线段树或点。在主席树上二分一下时间复杂度O(log2)
学完splay和fhq treap后觉得普通treap已经完全没有用了,不过treap重量平衡的性质还是非常妙的。
好像常数巨大。。。。附上3.7K代码
我数据结构还是太弱呀QAQ
看了myy的课件和vfk的题解
treap支持重量平衡,也就是他插入删除影响的节点数都是O(log) 的。
先说插入,我们先把点插入到最下面,然后往上旋,假设这个点转到祖先k的位置,那么影响节点为sizek 个,由于这个点的随机权值是sizek 个点中最小的,这个的概率是1sizek 的。期望是O(1),一个点有O(log) 个祖先,因此总期望影响节点数O(log)
对于删除,由于treap形态是由随机权值决定的,因此删除的数在treap上位置是随机的。由于treap中一个点的子树的期望大小是O(log) 的。因此是O(log) 的。
treap插入一个元素旋转的期望次数是O(1) 的。因为他的随机权值必须比上面的随机权值大才会旋转,这个次数期望O(1)
前面是几个保证复杂度的东西。
treap每个点代表一个数列中的点。每个点开一棵权值线段树维护子树中的所有点的权值。
由于旋转次数期望O(1),因此可以每次旋转之后直接更新一下信息,不需要最后重构子树里的线段树。
旋转x时,设y是x的父亲,那么旋转后x的线段树和旋转前y的线段树相同,只需更新一下y的线段树。
一开始想用O(log) 的线段树合并,不过线段树合并不支持内存回收,可能MLE,因此写了一个合并到底的O(log2) 。
查询时用前缀和相减的方法,可以得到log 个线段树或点。在主席树上二分一下时间复杂度O(log2)
学完splay和fhq treap后觉得普通treap已经完全没有用了,不过treap重量平衡的性质还是非常妙的。
好像常数巨大。。。。附上3.7K代码
#include <bits/stdc++.h> using namespace std; #define N 71000 #define M 25000000 #define S 70000 #define which(x) ch[fa[x]][1]==x #define ls ch[x][0] #define rs ch[x][1] struct node { int tp1,tp2,x; node(){} node(int tp1,int tp2,int x):tp1(tp1),tp2(tp2),x(x){} }st ; int top,n,q,a ; char s[11]; struct seg_tree { int ch[M][2],sum[M],cnt; queue<int>que; int ap() { if(que.empty())return ++cnt; int ret=que.front();que.pop(); ch[ret][1]=ch[ret][0]=0;sum[ret]=0; return ret; } void insert(int l,int r,int &x,int v,int type) { if(!x)x=ap();sum[x]+=type; if(l==r)return; int mid=(l+r)>>1; if(v<=mid)insert(l,mid,ch[x][0],v,type); else insert(mid+1,r,ch[x][1],v,type); } void insert(int &x,int v,int type) {insert(0,S,x,v,type);} int merge(int x,int y) { if(!x&&!y)return 0; int ret=ap(); ch[ret][0]=merge(ch[x][0],ch[y][0]); ch[ret][1]=merge(ch[x][1],ch[y][1]); sum[ret]=sum[x]+sum[y]; return ret; } void del(int x) { if(!x)return; que.push(x); del(ls);del(rs); } int work(int l,int r,int x) { if(l==r)return l; int t=0,mid=(l+r)>>1; for(int i=1;i<=top;i++) { if(st[i].tp2==1)t+=sum[ch[st[i].x][0]]*st[i].tp1; else if(st[i].x<=mid&&st[i].x>=l)t+=st[i].tp1; } if(t>=x) { for(int i=1;i<=top;i++) if(st[i].tp2==1)st[i].x=ch[st[i].x][0]; return work(l,mid,x); } else { for(int i=1;i<=top;i++) if(st[i].tp2==1)st[i].x=ch[st[i].x][1]; return work(mid+1,r,x-t); } } }tr1; struct treap { int ch [2],rt ,size ,rnd ,root,cnt,fa ,val ; void pushup(int x) { size[x]=size[ls]+size[rs]+1; rt[x]=tr1.merge(rt[ls],rt[rs]); tr1.insert(rt[x],val[x],1); } int build(int l,int r) { if(l>r)return 0; int mid=(l+r)>>1,x=++cnt; val[x]=a[mid];rnd[x]=rand()*rand(); ch[x][0]=build(l,mid-1); ch[x][1]=build(mid+1,r); pushup(x); return x; } int rotate(int x) { int y=fa[x],k=which(x); ch[y][k]=ch[x][k^1];ch[x][k^1]=y; ch[fa[y]][which(y)]=x; fa[x]=fa[y];fa[y]=x; fa[ch[y][k]]=y; tr1.del(rt[x]);rt[x]=rt[y]; pushup(y); size[x]=size[ls]+size[rs]+1; return x; } int insert(int x,int pos,int v) { if(!x) { x=++cnt;tr1.insert(rt[x],v,1); size[x]=1;rnd[x]=rand()*rand(); val[x]=v; return x; } if(pos<=size[ls]) { tr1.insert(rt[x],v,1);size[x]++; ls=insert(ls,pos,v);fa[ls]=x; if(rnd[ls]>rnd[x])x=rotate(ls); } else { tr1.insert(rt[x],v,1);size[x]++; rs=insert(rs,pos-size[ls]-1,v);fa[rs]=x; if(rnd[rs]>rnd[x])x=rotate(rs); } return x; } int change(int x,int pos,int v) { if(size[ls]+1==pos) { tr1.insert(rt[x],val[x],-1); tr1.insert(rt[x],v,1); return x; } int t; if(size[ls]>=pos)t=change(ls,pos,v); else t=change(rs,pos-size[ls]-1,v); tr1.insert(rt[x],val[t],-1); tr1.insert(rt[x],v,1); return t; } void find(int x,int pos,int tp) { if(!x||!pos)return; if(size[x]==pos) st[++top]=node(tp,1,rt[x]); else if(size[ls]>=pos) find(ls,pos,tp); else { st[++top]=node(tp,1,rt[ls]); st[++top]=node(tp,0,val[x]); find(rs,pos-size[ls]-1,tp); } } }tr2; int main() { scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]); tr2.root=tr2.build(1,n); scanf("%d",&q); for(int x,y,k,val,ans=0;q--;) { scanf("%s",s); if(s[0]=='Q') { scanf("%d%d%d",&x,&y,&k); x^=ans;y^=ans;k^=ans; top=0; tr2.find(tr2.root,x-1,-1); tr2.find(tr2.root,y,1); ans=tr1.work(0,S,k); printf("%d\n",ans); } if(s[0]=='M') { scanf("%d%d",&x,&val); x^=ans;val^=ans; int t=tr2.change(tr2.root,x,val); tr2.val[t]=val; } if(s[0]=='I') { scanf("%d%d",&x,&val); x^=ans;val^=ans; tr2.root=tr2.insert(tr2.root,x-1,val); } } return 0; }
相关文章推荐
- bzoj 3065: 带插入区间K小值 替罪羊树套主席树
- bzoj 3065: 带插入区间K小值 替罪羊树 && AC300
- [BZOJ]3065: 带插入区间K小值 块状链表
- bzoj 3065 - 带插入区间第k大
- bzoj3065带插入区间K小值
- [分块 块的分裂 || 替罪羊树套线段树] BZOJ 3065 带插入区间K小值
- 替罪羊树套线段树 【bzoj3065】 带插入区间k小值
- 【BZOJ】3065: 带插入区间K小值
- 【题解】BZOJ 3065: 带插入区间K小值——替罪羊树套线段树
- bzoj 3065 带插入区间k小值
- [BZOJ]3065: 带插入区间K小值
- BZOJ 3065 带插入区间K小值 替罪羊树套线段树
- BZOJ-3065 带插入区间K小值
- bzoj 3065: 带插入区间K小值(分块)
- bzoj 3065 带插入区间K小值
- BZOJ 3065 带插入区间K小值(sag套线段树)
- [bzoj3065] 带插入区间K小值
- bzoj3065 带插入区间K小值(替罪羊树套动态开点线段树)
- bzoj 3065 带插入区间k小值
- BZOJ 3065: 带插入区间K小值 替罪羊树套权值线段树 详解