1. 程式人生 > >靜態區間第k大 樹套樹解法

靜態區間第k大 樹套樹解法

i++ val pri math 1+n std -a 平衡樹 scanf

然而過不去你谷的模板

思路:
值域線段樹\([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\n",query(1,1,n,l,r,k));
    }
}
int main()
{
    init(),work();
    return 0;
}

2018.9.2

靜態區間第k大 樹套樹解法