您的位置:首页 > 理论基础 > 数据结构算法

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代码

#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;
}

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  数据结构