静态区间第k大 树套树解法

Posted ppprseter

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了静态区间第k大 树套树解法相关的知识,希望对你有一定的参考价值。

然而过不去你谷的模板

思路:
值域线段树([l,r])代表一棵值域在([l,r])范围内的点构成的一颗平衡树

平衡树的(BST)权值为点在序列中的位置

查询区间第(k)大值时

左区间在([l,r])范围内的树的大小与(k)比较

大了进去,小了减掉换一边

关于建树

递归建估计是(O(nlog^2n))


Code:

#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <vector>
const int N=1e5+10;
int ch[N*20][2],val[N*20],siz[N*20],pos[N*20],root[N<<2],tot;
#define ls ch[now][0]
#define rs ch[now][1]
int n,m,n_,a[N],b[N];
void updata(int now){siz[now]=siz[ls]+siz[rs]+1;}
void split(int now,int k,int &x,int &y)
{
    if(!now) {x=y=0;return;}
    if(pos[now]<=k)
        x=now,split(rs,k,rs,y);
    else
        y=now,split(ls,k,x,ls);
    updata(now);
}
int Merge(int x,int y)
{
    if(!x||!y) return x+y;
    if(val[x]<val[y])
    {
        ch[x][1]=Merge(ch[x][1],y);
        updata(x);
        return x;
    }
    else
    {
        ch[y][0]=Merge(x,ch[y][0]);
        updata(y);
        return y;
    }
}
int New(int k)
{
    val[++tot]=rand(),pos[tot]=k,siz[tot]=1;
    return tot;
}
void Insert(int id,int k)
{
    int x,y;
    split(root[id],k,x,y);
    root[id]=Merge(x,Merge(New(k),y));
}
int ask(int id,int l,int r)//询问区间
{
    int x,y,z,s;
    split(root[id],r,x,y);
    split(x,l-1,x,z);
    s=siz[z];
    root[id]=Merge(x,Merge(z,y));
    return s;
}
std::vector <int> loc[N];
void build(int id,int l,int r)
{
    if(l==r)
    {
        for(int i=0;i<loc[l].size();i++)
            Insert(id,loc[l][i]);
        return;
    }
    int mid=l+r>>1;
    build(id<<1,l,mid);
    build(id<<1|1,mid+1,r);
    for(int i=l;i<=r;i++)
        for(int j=0;j<loc[i].size();j++)
            Insert(id,loc[i][j]);
}
int query(int id,int l,int r,int ql,int qr,int k)
{
    if(l==r) return a[l];
    int mid=l+r>>1,cnt;
    if((cnt=ask(id<<1,ql,qr))>=k)
        return query(id<<1,l,mid,ql,qr,k);
    else
        return query(id<<1|1,mid+1,r,ql,qr,k-cnt);
}
void init()
{
    scanf("%d%d",&n_,&m);
    for(int i=1;i<=n_;i++) scanf("%d",a+i),b[i]=a[i];
    std::sort(a+1,a+1+n_);
    n=std::unique(a+1,a+1+n_)-a-1;
    for(int i=1;i<=n_;i++)
        loc[std::lower_bound(a+1,a+1+n,b[i])-a].push_back(i);
    build(1,1,n);
}
void work()
{
    for(int l,r,k,i=1;i<=m;i++)
    {
        scanf("%d%d%d",&l,&r,&k);
        printf("%d
",query(1,1,n,l,r,k));
    }
}
int main()
{
    init(),work();
    return 0;
}

2018.9.2


以上是关于静态区间第k大 树套树解法的主要内容,如果未能解决你的问题,请参考以下文章

数据结构(树套树):ZJOI 2013 K大数查询

bzoj 3196 树套树模板

树套树浅谈

luogu P4278ybt金牌导航4-5-2带插入区间K小值(树套树做法)

树套树

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