您的位置:首页 > 其它

bzoj3196 Tyvj 1730 二逼平衡树(树套树,线段树套splay/bit套动态开点线段树)

2018-02-25 22:27 411 查看
线段树套splay,看网上题解大部分说套splay是过不去的,需要优越的姿势才可以,本想着过不去再卡一卡优越的姿势的,然而过了qaq。

线段树维护区间,对于线段树的每个节点我们吊一棵splay维护区间内的权值。

操作1:查询k在区间[l,r]上的排名。

线段树上查询区间,去splay上查询小于k的有多少个,都加起来即可,再加1就是k的排名。

操作2:查询区间[l,r]上的排名为k的数。

这个操作比较精妙,我们先二分答案,然后去查mid的排名,调整答案即可。

操作3:修改x的权值为val。

相当于线段树单点修改,把原来的删了,再ins新的进去即可。

操作4:查询区间[l,r]上的k的前驱。

线段树上查询区间,去splay上查前驱,取max即可。

操作5:查询区间[l,r]上的k的后继。

线段树上查询区间,去splay上查后继,取min即可。

空间复杂度O((n+m)logn)O((n+m)logn)或者O(nlogn)O(nlogn)

操作2是O(logwlog2n)的吧,其它操作都是O(log2n)O(logwlog2n)的吧,其它操作都是O(log2n)

时间复杂度O(mlog2nlogw)O(mlog2nlogw)

不过为什么大家都说是O(nlog2n)O(nlog2n)的呢(迷

tips:要注意重复权值的处理哟,和普通平衡树一样的处理就好了

2.26upd: 树状数组套动态开点线段树

本以为空间怎么算都是过不去的,然而大家都说离散化权值以后,最多8e6的就够了。蒟蒻算了算树状数组所需的节点个数,好像确实比nlogn要少一半左右。动态开点线段树新建一条链均摊下来应该也要比logn小一些。但是具体能卡到多少并不是很会。

能开的下的话就很好做了,常数也很小。类似bzoj1901

2.28upd:写了一下线段树套treap,确实比splay快一些。

线段树套splay

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
#define ll long long
#define inf 2147483647
#define N 50010
inline char gc(){
static char buf[1<<16],*S,*T;
if(S==T){T=(S=buf)+fread(buf,1,1<<16,stdin);if(T==S) return EOF;}
return *S++;
}
inline int read(){
int x=0,f=1;char ch=gc();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=gc();}
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=gc();
return x*f;
}
int n,m,a
,rt[N<<2],fa[N*40],c[N*40][2],v[N*40],sz[N*40],cnt[N*40],owo=0;
int pos
,mx=0,ans;
inline void update(int x){
int l=c[x][0],r=c[x][1];
sz[x]=sz[l]+sz[r]+cnt[x];
}
inline void rotate(int x,int &k){
int y=fa[x],z=fa[y],l=x==c[y][1],r=l^1;
if(y==k) k=x;
else c[z][y==c[z][1]]=x;
fa[c[x][r]]=y;fa[y]=x;fa[x]=z;
c[y][l]=c[x][r];c[x][r]=y;update(y);update(x);
}
inline void splay(int x,int &k){
while(x!=k){
int y=fa[x],z=fa[y];
if(y!=k){
if(x==c[y][1]^y==c[z][1]) rotate(x,k);
else rotate(y,k);
}rotate(x,k);
}
}
inline int find(int p,int x){
if(v[p]==x) return p;
if(x<v[p]) return find(c[p][0],x);
return find(c[p][1],x);
}
inline void ins(int &p,int x,int Fa,int id){
if(!p){
p=++owo;fa[p]=Fa;c[p][0]=c[p][1]=0;v[p]=x;sz[p]=cnt[p]=1;splay(p,rt[id]);return;
}if(v[p]==x){cnt[p]++;sz[p]++;splay(p,rt[id]);return;}
if(x<v[p]) ins(c[p][0],x,p,id);
else ins(c[p][1],x,p,id);
}
inline int qrank(int p,int x){//查询比x小的数有几个
if(!p) return 0;
if(x<v[p]) return qrank(c[p][0],x);
if(x==v[p]) return sz[c[p][0]];
return sz[c[p][0]]+cnt[p]+qrank(c[p][1],x);
}
inline void del(int id,int val){
int x=find(rt[id],val);splay(x,rt[id]);
if(cnt[x]>1){cnt[x]--;sz[x]--;return;}
if(c[x][0]*c[x][1]==0){
rt[id]=c[x][0]+c[x][1];fa[rt[id]]=c[x][0]=c[x][1]=0;return;
}int pre=c[x][0],succ=c[x][1];
while(c[pre][1]) pre=c[pre][1];while(c[succ][0]) succ=c[succ][0];
splay(pre,rt[id]);splay(succ,c[pre][1]);c[succ][0]=fa[x]=0;
update(succ);update(pre);
}
inline int getpre(int rt,int x){
int res=-inf,p=rt;
while(p){
if(v[p]<x) res=v[p],p=c[p][1];
else p=c[p][0];
}return res;
}
inline int getsucc(int rt,int x){
int res=inf,p=rt;
while(p){
if(v[p]>x) res=v[p],p=c[p][0];
else p=c[p][1];
}return res;
}
inline void seg_ins(int p,int l,int r,int x,int val){
ins(rt[p],val,0,p);
if(l==r) return;int mid=l+r>>1;
if(x<=mid) seg_ins(p<<1,l,mid,x,val);
else seg_ins(p<<1|1,mid+1,r,x,val);
}
inline int seg_rank(int p,int l,int r,int x,int y,int val){
if(x<=l&&r<=y) return qrank(rt[p],val);
int mid=l+r>>1,res=0;
if(x<=mid) res+=seg_rank(p<<1,l,mid,x,y,val);
if(y>mid) res+=seg_rank(p<<1|1,mid+1,r,x,y,val);
return res;
}
inline void seg_change(int p,int l,int r,int x,int val){
del(p,a[x]);ins(rt[p],val,0,p);
if(l==r) return;int mid=l+r>>1;
if(x<=mid) seg_change(p<<1,l,mid,x,val);
else seg_change(p<<1|1,mid+1,r,x,val);
}
inline int getkth(int x,int y,int k){
int l=0,r=mx;
while(l<=r){
int mid=l+r>>1;
if(seg_rank(1,1,n,x,y,mid)<k) l=mid+1;
else r=mid-1;
}return l-1;
}
inline void seg_pre(int p,int l,int r,int x,int y,int val){
if(x<=l&&r<=y){ans=max(ans,getpre(rt[p],val));return;}
int mid=l+r>>1;
if(x<=mid) seg_pre(p<<1,l,mid,x,y,val);
if(y>mid) seg_pre(p<<1|1,mid+1,r,x,y,val);
}
inline void seg_succ(int p,int l,int r,int x,int y,int val){
if(x<=l&&r<=y){ans=min(ans,getsucc(rt[p],val));return;}
int mid=l+r>>1;
if(x<=mid) seg_succ(p<<1,l,mid,x,y,val);
if(y>mid) seg_succ(p<<1|1,mid+1,r,x,y,val);
}
int main(){
//  freopen("a.in","r",stdin);
n=read();m=read();
for(int i=1;i<=n;++i) a[i]=read(),seg_ins(1,1,n,i,a[i]),mx=max(mx,a[i]);
while(m--){
int op=read();
if(op==3){int x=read(),val=read();seg_change(1,1,n,x,val);a[x]=val;mx=max(mx,val);continue;}
int l=read(),r=read(),k=read();
if(op==1) printf("%d\n",seg_rank(1,1,n,l,r,k)+1);
if(op==2) printf("%d\n",getkth(l,r,k));
if(op==4){ans=-inf;seg_pre(1,1,n,l,r,k);printf("%d\n",ans);}
if(op==5){ans=inf;seg_succ(1,1,n,l,r,k);printf("%d\n",ans);}
}return 0;
}


树状数组套动态开点线段树

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
#define ll long long
#define inf 2147483647
#define N 50010
inline char gc(){
static char buf[1<<16],*S,*T;
if(S==T){T=(S=buf)+fread(buf,1,1<<16,stdin);if(T==S) return EOF;}
return *S++;
}
inline int read(){
int x=0,f=1;char ch=gc();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=gc();}
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=gc();
return x*f;
}
int n,m,aa[N<<1],a
,rt
,num=0,owo=0,p1
,p2
,n1,n2;
struct node{
int lc,rc,sum;
}tr[N*80*2];
struct oper{
int op,l,r,k;
}e
;
inline void add(int &p,int l,int r,int x,int val){
if(!p) p=++owo;tr[p].sum+=val;
if(l==r) return;int mid=l+r>>1;
if(x<=mid) add(tr[p].lc,l,mid,x,val);
else add(tr[p].rc,mid+1,r,x,val);
}
inline void bit_add(int x,int pos,int val){
for(;x<=n;x+=x&-x) add(rt[x],1,num,pos,val);
}
inline void gao1(int x){
n1=0;for(;x;x-=x&-x) p1[++n1]=rt[x];
}
inline void gao2(int x){
n2=0;for(;x;x-=x&-x) p2[++n2]=rt[x];
}
inline int qless(int l,int r,int x){
if(l==r) return 0;
int mid=l+r>>1,res=0;
if(x<=mid){
for(int i=1;i<=n1;++i) p1[i]=tr[p1[i]].lc;
for(int i=1;i<=n2;++i) p2[i]=tr[p2[i]].lc;
return qless(l,mid,x);
}else{
for(int i=1;i<=n1;++i) res+=tr[tr[p1[i]].lc].sum;
for(int i=1;i<=n2;++i) res-=tr[tr[p2[i]].lc].sum;
for(int i=1;i<=n1;++i) p1[i]=tr[p1[i]].rc;
for(int i=1;i<=n2;++i) p2[i]=tr[p2[i]].rc;
return res+qless(mid+1,r,x);
}
}
inline int qmore(int l,int r,int x){
if(l==r) return 0;
int mid=l+r>>1,res=0;
if(x<mid+1){
for(int i=1;i<=n1;++i) res+=tr[tr[p1[i]].rc].sum;
for(int i=1;i<=n2;++i) res-=tr[tr[p2[i]].rc].sum;
for(int i=1;i<=n1;++i) p1[i]=tr[p1[i]].lc;
for(int i=1;i<=n2;++i) p2[i]=tr[p2[i]].lc;
return res+qmore(l,mid,x);
}else{
for(int i=1;i<=n1;++i) p1[i]=tr[p1[i]].rc;
for(int i=1;i<=n2;++i) p2[i]=tr[p2[i]].rc;
return qmore(mid+1,r,x);
}
}
inline int qkth(int l,int r,int k){
if(l==r) return l;
int res=0,mid=l+r>>1;
for(int i=1;i<=n1;++i) res+=tr[tr[p1[i]].lc].sum;
for(int i=1;i<=n2;++i) res-=tr[tr[p2[i]].lc].sum;
if(k<=res){
for(int i=1;i<=n1;++i) p1[i]=tr[p1[i]].lc;
for(int i=1;i<=n2;++i) p2[i]=tr[p2[i]].lc;
return qkth(l,mid,k);
}
for(int i=1;i<=n1;++i) p1[i]=tr[p1[i]].rc;
for(int i=1;i<=n2;++i) p2[i]=tr[p2[i]].rc;
return qkth(mid+1,r,k-res);
}
int main(){
//  freopen("a.in","r",stdin);
n=read();m=read();num=n;
for(int i=1;i<=n;++i) aa[i]=a[i]=read();
for(int i=1;i<=m;++i){
e[i].op=read();e[i].l=read();e[i].r=read();
if(e[i].op==3){aa[++num]=e[i].r;continue;}
e[i].k=read();if(e[i].op!=2) aa[++num]=e[i].k;
}sort(aa+1,aa+num+1);num=unique(aa+1,aa+num+1)-aa-1;
for(int i=1;i<=n;++i) a[i]=lower_bound(aa+1,aa+num+1,a[i])-aa,bit_add(i,a[i],1);
for(int i=1;i<=m;++i){
if(e[i].op==1){
e[i].k=lower_bound(aa+1,aa+num+1,e[i].k)-aa;
gao1(e[i].r);gao2(e[i].l-1);
printf("%d\n",qless(1,num,e[i].k)+1);continue;
}if(e[i].op==2){
gao1(e[i].r);gao2(e[i].l-1);
printf("%d\n",aa[qkth(1,num,e[i].k)]);continue;
}if(e[i].op==3){
e[i].r=lower_bound(aa+1,aa+num+1,e[i].r)-aa;
int x=e[i].l;bit_add(x,a[x],-1);
a[x]=e[i].r;bit_add(x,a[x],1);continue;
}if(e[i].op==4){
e[i].k=lower_bound(aa+1,aa+num+1,e[i].k)-aa;
gao1(e[i].r);gao2(e[i].l-1);
int pos=qless(1,num,e[i].k);
if(!pos){printf("%d\n",-inf);continue;}
gao1(e[i].r);gao2(e[i].l-1);
printf("%d\n",aa[qkth(1,num,pos)]);continue;
}if(e[i].op==5){
e[i].k=lower_bound(aa+1,aa+num+1,e[i].k)-aa;
gao1(e[i].r);gao2(e[i].l-1);
int pos=qmore(1,num,e[i].k),sz=e[i].r-e[i].l+1;
if(!pos){printf("%d\n",inf);continue;}
gao1(e[i].r);gao2(e[i].l-1);
printf("%d\n",aa[qkth(1,num,sz-pos+1)]);continue;
}
}return 0;
}


线段树套treap

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
#define ll long long
#define inf 2147483647
#define N 50010
inline char gc(){
static char buf[1<<16],*S,*T;
if(S==T){T=(S=buf)+fread(buf,1,1<<16,stdin);if(T==S) return EOF;}
return *S++;
}
inline int read(){
int x=0,f=1;char ch=gc();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=gc();}
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=gc();
return x*f;
}
int n,m,a
,rt[N<<2],ls[N*40],rs[N*40],v[N*40],sz[N*40],cnt[N*40],rnd[N*40],owo=0;
int pos
,mx=0,ans;
inline void update(int p){sz[p]=sz[ls[p]]+sz[rs[p]]+cnt[p];}
inline void rturn(int &y){int x=ls[y];ls[y]=rs[x];rs[x]=y;update(y);update(x);y=x;}
inline void lturn(int &y){int x=rs[y];rs[y]=ls[x];ls[x]=y;update(y);update(x);y=x;}
inline void ins(int &p,int x){
if(!p){p=++owo;v[p]=x;sz[p]=cnt[p]=1;rnd[p]=rand();return;}
if(v[p]==x){cnt[p]++;sz[p]++;return;}++sz[p];
if(x<v[p]){ins(ls[p],x);if(rnd[ls[p]]<rnd[p]) rturn(p);}
else {ins(rs[p],x);if(rnd[rs[p]]<rnd[p]) lturn(p);}
}
inline int qrank(int p,int x){//查询比x小的数有几个
if(!p) return 0;
if(x<v[p]) return qrank(ls[p],x);
if(x==v[p]) return sz[ls[p]];
return sz[ls[p]]+cnt[p]+qrank(rs[p],x);
}
inline void del(int &p,int x){
if(v[p]==x){
if(cnt[p]>1) cnt[p]--,sz[p]--;
else if(ls[p]*rs[p]==0) p=ls[p]+rs[p];
else if(rnd[ls[p]]<rnd[rs[p]]) rturn(p),del(p,x);
else lturn(p),del(p,x);return;
}sz[p]--;
if(x<v[p]) del(ls[p],x);
else del(rs[p],x);
}
inline int getpre(int rt,int x){
int res=-inf,p=rt;
while(p){
if(v[p]<x) res=v[p],p=rs[p];
else p=ls[p];
}return res;
}
inline int getsucc(int rt,int x){
int res=inf,p=rt;
while(p){
if(v[p]>x) res=v[p],p=ls[p];
else p=rs[p];
}return res;
}
inline void seg_ins(int p,int l,int r,int x,int val){
ins(rt[p],val);
if(l==r) return;int mid=l+r>>1;
if(x<=mid) seg_ins(p<<1,l,mid,x,val);
else seg_ins(p<<1|1,mid+1,r,x,val);
}
inline int seg_rank(int p,int l,int r,int x,int y,int val){
if(x<=l&&r<=y) return qrank(rt[p],val);
int mid=l+r>>1,res=0;
if(x<=mid) res+=seg_rank(p<<1,l,mid,x,y,val);
if(y>mid) res+=seg_rank(p<<1|1,mid+1,r,x,y,val);
return res;
}
inline void seg_change(int p,int l,int r,int x,int val){
del(rt[p],a[x]);ins(rt[p],val);
if(l==r) return;int mid=l+r>>1;
if(x<=mid) seg_change(p<<1,l,mid,x,val);
else seg_change(p<<1|1,mid+1,r,x,val);
}
inline int getkth(int x,int y,int k){
int l=0,r=mx;
while(l<=r){
int mid=l+r>>1;
if(seg_rank(1,1,n,x,y,mid)<k) l=mid+1;
else r=mid-1;
}return l-1;
}
inline void seg_pre(int p,int l,int r,int x,int y,int val){
if(x<=l&&r<=y){ans=max(ans,getpre(rt[p],val));return;}
int mid=l+r>>1;
if(x<=mid) seg_pre(p<<1,l,mid,x,y,val);
if(y>mid) seg_pre(p<<1|1,mid+1,r,x,y,val);
}
inline void seg_succ(int p,int l,int r,int x,int y,int val){
if(x<=l&&r<=y){ans=min(ans,getsucc(rt[p],val));return;}
int mid=l+r>>1;
if(x<=mid) seg_succ(p<<1,l,mid,x,y,val);
if(y>mid) seg_succ(p<<1|1,mid+1,r,x,y,val);
}
int main(){
//  freopen("a.in","r",stdin);
n=read();m=read();srand(20000712);
for(int i=1;i<=n;++i) a[i]=read(),seg_ins(1,1,n,i,a[i]),mx=max(mx,a[i]);
while(m--){
int op=read();
if(op==3){int x=read(),val=read();seg_change(1,1,n,x,val);a[x]=val;mx=max(mx,val);continue;}
int l=read(),r=read(),k=read();
if(op==1) printf("%d\n",seg_rank(1,1,n,l,r,k)+1);
if(op==2) printf("%d\n",getkth(l,r,k));
if(op==4){ans=-inf;seg_pre(1,1,n,l,r,k);printf("%d\n",ans);}
if(op==5){ans=inf;seg_succ(1,1,n,l,r,k);printf("%d\n",ans);}
}return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: