习题:二逼平衡树(树套树)
Posted loney-s
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了习题:二逼平衡树(树套树)相关的知识,希望对你有一定的参考价值。
题目
思路
挺好的一道树套树的板子题
因为笔者过于菜鸡其实是懒
写了BIT套主席树
求区间第k大,前驱和后驱都是主席树的基本操作
所有此处要阐述的是修改操作
如果是直接单纯用主席树
那么修改一个节点就要修改n棵树
相当于单次修改的时间复杂度为(O(n*log_n))
但是我们仔细思考一下整个过程,
我们所需要的只是前L-1次操作和前R次操作
相当于一个前缀,所以就可以用BIT来维护
每一个BIT来维护的其实就是每一次修改操作之后的权值线段树
这样我们就将修改的时间复杂度压缩为(O(log_n*log_n))
第一个log是BIT,第二个log是权值线段树
相应的,询问操作就要变为(O(log_n*log_n))
因为每到树上一个节点就要用树状数组来算
因为权值线段树上的(log)是与整个值域相关的,
所以笔者建议追求极致的Oier们进行离散化
代码
#include<iostream>
#include<algorithm>
#include<climits>
using namespace std;
struct request
{
int opt;
int l;
int r;
int k;
}q[50005];
struct node
{
int lson;
int rson;
int siz;
}tre[50005<<7];
int n,m;
int cnt;
int tot;
int totx;
int toty;
int a[50005];
int b[100005];
int x[50005];
int y[50005];
int rt[50005];
int lowbit(int x)
{
return x&(-x);
}
void insert(int &x,int pos,int val,int l=1,int r=cnt)
{
//cout<<"insert:"<<x<<' '<<pos<<' '<<val<<' '<<l<<' '<<r<<'
';
if(!x)
x=++tot;
tre[x].siz+=val;
if(l==r)
return;
int mid=(l+r)>>1;
if(pos<=mid)
insert(tre[x].lson,pos,val,l,mid);
else
insert(tre[x].rson,pos,val,mid+1,r);
}
void modify(int x,int v)
{
int k=lower_bound(b+1,b+cnt+1,a[x])-b;
for(int i=x;i<=n;i+=lowbit(i))
insert(rt[i],k,v);
}
void solve_sum(int &s)
{
for(int i=1;i<=totx;i++)
s-=tre[tre[x[i]].lson].siz;
for(int i=1;i<=toty;i++)
s+=tre[tre[y[i]].lson].siz;
}
void solve_ls()
{
for(int i=1;i<=totx;i++)
x[i]=tre[x[i]].lson;
for(int i=1;i<=toty;i++)
y[i]=tre[y[i]].lson;
}
void solve_rs()
{
for(int i=1;i<=totx;i++)
x[i]=tre[x[i]].rson;
for(int i=1;i<=toty;i++)
y[i]=tre[y[i]].rson;
}
void prepare(int l,int r)
{
for(int i=l-1;i>0;i-=lowbit(i))
x[++totx]=rt[i];
for(int i=r;i>0;i-=lowbit(i))
y[++toty]=rt[i];
}
int solve_kth(int k,int l=1,int r=cnt)
{
//cout<<"solve_kth:"<<k<<' '<<l<<' '<<r<<'
';
if(l==r)
return l;
int mid=(l+r)>>1;
int s=0;
solve_sum(s);
if(k<=s)
{
solve_ls();
return solve_kth(k,l,mid);
}
else
{
solve_rs();
return solve_kth(k-s,mid+1,r);
}
}
void Solve_kth(int l,int r,int k)
{
totx=toty=0;
prepare(l,r);
cout<<b[solve_kth(k)]<<'
';
}
int solve_rank(int x,int val,int l=1,int r=cnt)
{
//cout<<"solve_rank:"<<x<<' '<<val<<' '<<l<<' '<<r<<'
';
if(!x)
return 0;
if(l==r)
{
return 0;
}
int mid=(l+r)>>1;
if(val<=mid)
return solve_rank(tre[x].lson,val,l,mid);
else
return tre[tre[x].lson].siz+solve_rank(tre[x].rson,val,mid+1,r);
}
void Solve_rank(int l,int r,int val)
{
int s=0;
int x=lower_bound(b+1,b+cnt+1,val)-b;
for(int i=l-1;i>0;i-=lowbit(i))
s-=solve_rank(rt[i],x);
for(int i=r;i>0;i-=lowbit(i))
s+=solve_rank(rt[i],x);
cout<<s+1<<'
';
}
void solve_pre(int l,int r,int val)
{
int s=0;
int x=lower_bound(b+1,b+cnt+1,val)-b;
for(int i=l-1;i>0;i-=lowbit(i))
s-=solve_rank(rt[i],x);
for(int i=r;i>0;i-=lowbit(i))
s+=solve_rank(rt[i],x);
if(!s)
cout<<"-2147483647"<<'
';
else
Solve_kth(l,r,s);
}
void solve_suf(int l,int r,int val)
{
int s=0;
int x=lower_bound(b+1,b+cnt+1,val)-b+1;
for(int i=l-1;i>0;i-=lowbit(i))
s-=solve_rank(rt[i],x);
for(int i=r;i>0;i-=lowbit(i))
s+=solve_rank(rt[i],x);
if(s>r-l)
cout<<"2147483647"<<'
';
else
Solve_kth(l,r,s+1);
}
int main()
{
ios::sync_with_stdio(false);
//freopen("testdata.in","r",stdin);
//freopen("ans.out","w",stdout);
cin>>n>>m;
for(int i=1;i<=n;i++)
{
cin>>a[i];
b[++cnt]=a[i];
}
for(int i=1;i<=m;i++)
{
cin>>q[i].opt>>q[i].l>>q[i].r;
if(q[i].opt!=3)
cin>>q[i].k;
if(q[i].opt==3)
b[++cnt]=q[i].r;
else if(q[i].opt!=2)
b[++cnt]=q[i].k;
}
sort(b+1,b+cnt+1);
cnt=unique(b+1,b+cnt+1)-b-1;
for(int i=1;i<=n;i++)
modify(i,1);
for(int i=1;i<=m;i++)
{
if(q[i].opt==1)
Solve_rank(q[i].l,q[i].r,q[i].k);
if(q[i].opt==2)
Solve_kth(q[i].l,q[i].r,q[i].k);
if(q[i].opt==3)
{
modify(q[i].l,-1);
a[q[i].l]=q[i].r;
modify(q[i].l,1);
}
if(q[i].opt==4)
solve_pre(q[i].l,q[i].r,q[i].k);
if(q[i].opt==5)
solve_suf(q[i].l,q[i].r,q[i].k);
//cout<<i<<'
';
}
return 0;
}
以上是关于习题:二逼平衡树(树套树)的主要内容,如果未能解决你的问题,请参考以下文章