L. Lookup Performance(二分+主席树)
Posted issue是fw
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了L. Lookup Performance(二分+主席树)相关的知识,希望对你有一定的参考价值。
给定一颗二叉搜索树
q q q次询问给定区间 [ l , r ] [l,r] [l,r],问从根节点执行 l o o k u p ( 1 , l , r ) lookup(1,l,r) lookup(1,l,r)函数共执行多少次
设节点 x x x中权值最小权值为 m i x mi_x mix,最大的为 m x x mx_x mxx
如果能访问到节点 x x x,说明 x x x的父节点 r r r一定
①.不满足 L < = m i r & & m x r < = R L<=mi_r\\&\\&mx_r<=R L<=mir&&mxr<=R
②.不满足 m x r < L mx_r<L mxr<L或 R < m i r R<mi_r R<mir
①好办,我们把所有节点的 m i r mi_r mir装进数组 z z z中,把 m x r mx_r mxr装进 y y y
二分找到多少节点的 L < = m i r L<=mi_r L<=mir,二分找到多少节点的 m x r < = R mx_r<=R mxr<=R
②的话,我们按照 m i r mi_r mir排序,按照 m i r mi_r mir的排名为索引, m x r mx_r mxr为节点权值插入主席树
那么对于 [ L , R ] [L,R] [L,R]区间,先二分一个 i d id id使得 r ∈ [ i d , n ] r\\in[id,n] r∈[id,n]的 m i r mi_r mir都大于等于 L L L
那么就是要求这个区间有多少权值小于等于 R R R
主席树模板题
#include <bits/stdc++.h>
using namespace std;
#define mid ((l+r)>>1)
const int maxn = 1e7+19;
const int inf = 1e9+1;
vector<int>vec[maxn],z,y;
typedef pair<int,int>p;
vector<p>both;
int k[maxn],n,mi[maxn],mx[maxn];
void dfs(int u)
{
mi[u] = k[u], mx[u] = k[u];
for(auto v:vec[u] )
{
dfs( v );
mi[u] = min( mi[u],mi[v] );
mx[u] = max( mx[u],mx[v] );
}
}
int siz[maxn],ls[maxn],rs[maxn],id,root[maxn];
void update(int &rt,int pre,int l,int r,int val)
{
rt = ++id;
ls[rt] = ls[pre], rs[rt] = rs[pre], siz[rt] = siz[pre]+1;
if( l==r ) return;
if( val<=mid ) update(ls[rt],ls[pre],l,mid,val);
else update( rs[rt],rs[pre],mid+1,r,val );
}
int ask(int rt,int pre,int l,int r,int L,int R)//查询权值为[-inf,val]之间的点数
{
if( l>=L && r<=R ) return siz[rt]-siz[pre];
if( l>R || r<L ) return 0;
if( l==r ) return 1;
return ask( ls[rt],ls[pre],l,mid,L,R)+ask( rs[rt],rs[pre],mid+1,r,L,R );
}
int main()
{
int n; cin >> n;
for(int i=1;i<=n;i++)
{
int l,r; scanf("%d%d%d",&l,&r,&k[i]);
if( l ) vec[i].push_back( l );
if( r ) vec[i].push_back( r );
}
dfs( 1 );
for(int i=1;i<=n;i++)
{
z.push_back( mi[i] ),y.push_back( mx[i] );
both.push_back( p(mi[i],mx[i] ) );
}
sort( both.begin(),both.end() );
sort( z.begin(),z.end() );
sort( y.begin(),y.end() );
for(int i=1;i<=n;i++)
update( root[i],root[i-1],-inf,inf,both[i-1].second );
int q; cin >> q;
while( q-- )
{
int l,r; scanf("%d%d",&l,&r);
int ld = n-(upper_bound(z.begin(),z.end(),r)-z.begin()+1)+1;
int rd = lower_bound(y.begin(),y.end(),l)-y.begin();
int id = lower_bound(z.begin(),z.end(),l)-z.begin()+1;
// cout << ask( root[n],root[id-1],-inf,inf,-inf,r ) << "sssssssss" << endl;
int now = n-ld-rd-ask(root[n],root[id-1],-inf,inf,-inf,r);
printf("%d\\n",now<<1|1 );
}
}
以上是关于L. Lookup Performance(二分+主席树)的主要内容,如果未能解决你的问题,请参考以下文章
Performance - Inefficient use of keySet iterator instead of entrySet iterator