您的位置:首页 > 其它

[BZOJ3585][清华集训2014]mex 主席树

2017-12-12 20:42 447 查看
考虑用主席树维护到第i个位置时,每个数最后一次出现位置,也就是说维护的是n棵权值线段树,线段树上每个节点表示值域在此之内的每个数最后一次出现位置的最小值。

那么一个询问(l,r)就是在第r棵线段树上查最小的且上一次出现位置小于l的数,经典操作。

注意离散化的时候要把每个值和它+1扔进去离散化,而且要去重,因为不能破坏整数的连续性。

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=200010;
int a[maxn],z[maxn<<1],n,m;
struct tree;
tree *NUL;
struct tree
{
int mi;
tree *so[2];
tree(){mi=0;so[0]=so[1]=NUL;}
void update(){mi=min(so[0]->mi,so[1]->mi);}
void build(tree *lst,int p,int l,int r)
{
if(l==r) {mi=p;return;}
int mid=(l+r)>>1;bool b=(a[p]>mid);
int lx=b?mid+1:l,rx=b?r:mid;
so[b^1]=lst->so[b^1];
(so[b]=new tree)->build(lst->so[b],p,lx,rx);
update();
}
int query(int p,int l,int r)
{
if(l==r||this==NUL) return l;
int mid=(l+r)>>1;
if(so[0]->mi<p) so[0]->query(p,l,mid);
else so[1]->query(p,mid+1,r);
}
}*rt[maxn];
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
z[2*i-1]=a[i];z[2*i]=a[i]+1;
}
sort(z+1,z+2*n+1);
int sz;
sz=unique(z+1,z+2*n+1)-z-1;
for(int i=1;
f9a8
i<=n;i++)
a[i]=lower_bound(z+1,z+sz+1,a[i])-z;
NUL=new tree;NUL->so[0]=NUL->so[1]=NUL;
rt[0]=new tree;
for(int i=1;i<=n;i++)
(rt[i]=new tree)->build(rt[i-1],i,1,sz);
while(m--)
{
int l,r;
scanf("%d%d",&l,&r);
printf("%d\n",z[rt[r]->query(l,1,sz)]);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: