あなたは会長の木の詳細な研究たい場合はポータルを。
説明:
列の所定の数(\ \ {A_N \} \) 、閉区間シーク\([L、R] \ ) の\(K \)少数です。
方法:
離散データは、まず、次に重みに従ってツリーラインを構築します。
見つけること\([1、P] \ ) の\(k個の\)が小さい場合、ルート・プロセスから始まります。定義\(Son_は{左} \)左息子のセットを表し\(右Son_ {} \)右息子の集合を表します。場合は\(| Son_ {左} | \ GE kが\) の記述\(K \)の左部分木に小さな数字は、最初の左部分木を見て、再帰的にダウン更新、新規のルートに彼の息子を残しました\(K \)の小さな数字は、逆に、説明に\(K \)の右部分木に小さな数字の左部分木を見て、再帰的にダウン更新、新規のルートに彼の息子を残した\(K-を| Son_ {左} | \)少数。
ビットを展開し、成果が得られるの前処理しましょう\(N + 1 \) (初期セグメントツリーを含む)ツリーラインのバージョンを、番号(\ N- SIM \ 0)\。
プレフィックス思想と問い合わせを満たすために木の社長は、前に述べたように、私たちが求める([L、R] \ \ ) の\(k個\)小さな値は、使用することができますsum[r]-sum[l-1]
。
コード:
#include<bits/stdc++.h>
#define int long long
#define Maxn 200010
using namespace std;
inline void read(int &x)
{
int f=1;x=0;char s=getchar();
while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
x*=f;
}
int n,m;
struct Segtree
{
int ls,rs,sum;
}tree[Maxn<<5];
int rt[Maxn];
int a[Maxn],ins[Maxn];
int len,tot=0;
inline void Init(){tot=0;}
inline int getid(const int &x)
{
return lower_bound(ins+1,ins+len+1,x)-ins;
}
inline void pushup(int rt)
{
tree[rt].sum=tree[tree[rt].ls].sum+tree[tree[rt].rs].sum;
}
inline int build(int l,int r)
{
int rt=++tot;
if(l==r)
{
tree[rt].sum=0;
return rt;
}
int mid=(l+r)/2;
tree[rt].ls=build(l,mid);
tree[rt].rs=build(mid+1,r);
pushup(rt);
return rt;
}
int update(int k,int l,int r,int root,int val)
{
int rt=++tot;
tree[rt]=tree[root];
if(l==k&&r==k)
{
tree[rt].sum+=val;
return rt;
}
int mid=(l+r)/2;
if(k<=mid) tree[rt].ls=update(k,l,mid,tree[rt].ls,val);
else tree[rt].rs=update(k,mid+1,r,tree[rt].rs,val);
pushup(rt);
return rt;
}
int query(int u,int v,int l,int r,int k)
{
if(l==r) return l;
int mid=(l+r)/2,x=tree[tree[v].ls].sum-tree[tree[u].ls].sum;
if(k<=x) return query(tree[u].ls,tree[v].ls,l,mid,k);
else return query(tree[u].rs,tree[v].rs,mid+1,r,k-x);
}
signed main()
{
Init();
read(n),read(m);
for(int i=1;i<=n;i++)
{
read(a[i]);
}
memcpy(ins,a,sizeof(ins));
sort(ins+1,ins+n+1);
len=unique(ins+1,ins+n+1)-ins-1;
rt[0]=build(1,len);
for(int i=1;i<=n;i++)
{
rt[i]=update(getid(a[i]),1,len,rt[i-1],1);
}
while(m--)
{
int l,r,k;
read(l),read(r),read(k);
printf("%lld\n",ins[query(rt[l-1],rt[r],1,len,k)]);
}
return 0;
}
警告:
ls[]
、rs[]
、sum[]
乗算さおよび他のアレイ\(^ 5 \ 2) 。- 離散テイク
lower_bound
時間、マイナス任意の先頭の0は最後のアドレスではなく、1から始まるアドレスです。(つまりlower_bound(ins+1,ins+n+1,x)-ins
、ではありませんlower_bound(ins+1,ins+n+1,x)-ins-1
) - 再帰クエリ右サブツリー検索\を(K-| Son_ {左} | \) 小さな、代わりに\(k個\)小さな。