刚学主席树,写篇题解加强记忆。
思路:和主席树模板一样,先离散化,再建树,其实只需要把主席树模板的AC代码最后的查询还有数组的大小改一改。
代码:
#include<bits/stdc++.h>
using namespace std;
const int N=500001;//唯二和主席树模板不一样的地方
int n,q,m,cnt;
int a[N],b[N],t[N];
struct sb
{
int s,l,r;
}tre[N<<5];
int build(int l,int r)//以下全部和主席树模板一样
{
int p=++cnt;
if(l<r)
{
int mid=(l+r)>>1;
tre[p].l=build(l,mid);
tre[p].r=build(mid+1,r);
}
return p;
}
int update(int p1,int l,int r,int x)
{
int p=++cnt;
tre[p].l=tre[p1].l;
tre[p].r=tre[p1].r;
tre[p].s=tre[p1].s+1;
if(l<r)
{
int mid=(l+r)>>1;
if(x<=mid)tre[p].l=update(tre[p1].l,l,mid,x);else tre[p].r=update(tre[p1].r,mid+1,r,x);
}
return p;
}//以上全部和主席树模板一样
int query(int u,int v,int l,int r,int k)//唯二和主席树模板不一样的地方,k表示区间长度的一半
{
if(l>=r)return l;
int l1=tre[tre[v].l].s-tre[tre[u].l].s,r1=tre[tre[v].r].s-tre[tre[u].r].s;//计算当前区间大于等于l小于等于mid的数字的数量和大于mid小于等于r的数字的数量
int mid=(l+r)>>1;
if(l1>k)return query(tre[u].l,tre[v].l,l,mid,k);//如果大于等于l小于等于mid的数字的数量超过一半就往下查询
if(r1>k)return query(tre[u].r,tre[v].r,mid+1,r,k);//同上
return 0;//否则说明该区间中不存在出现数量超过一半的数,返回0
}
int main()//以下全部和主席树模板一样
{
scanf("%d%d",&n,&q);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
b[i]=a[i];
}
sort(b+1,b+n+1);
m=unique(b+1,b+n+1)-b-1;
t[0]=build(1,m);
for(int i=1;i<=n;i++)
{
int l=lower_bound(b+1,b+m+1,a[i])-b;
t[i]=update(t[i-1],1,m,l);
}
while(q--)
{
int a1,a2;
scanf("%d%d",&a1,&a2);
printf("%d\n",b[query(t[a1-1],t[a2],1,m,(a2-a1+1)/2)]);//查询
}
}//以上全部和主席树模板一样