习题:二逼平衡树(树套树)

题目

传送门

思路

挺好的一道树套树的板子题

因为笔者过于菜鸡其实是懒

写了BIT套主席树

求区间第k大,前驱和后驱都是主席树的基本操作

所有此处要阐述的是修改操作

如果是直接单纯用主席树

那么修改一个节点就要修改n棵树

相当于单次修改的时间复杂度为\(O(n*log_n)\)

但是我们仔细思考一下整个过程,

我们所需要的只是前L-1次操作和前R次操作

扫描二维码关注公众号,回复: 8074484 查看本文章

相当于一个前缀,所以就可以用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<<'\n';
    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<<'\n';
    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)]<<'\n';
}
int solve_rank(int x,int val,int l=1,int r=cnt)
{
    //cout<<"solve_rank:"<<x<<' '<<val<<' '<<l<<' '<<r<<'\n';   
    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<<'\n';
}
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"<<'\n';
    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"<<'\n';
    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<<'\n';
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/loney-s/p/11985753.html
今日推荐