题目描述
给一个长度为n的序列a。1≤a[i]≤n。
m组询问,每次询问一个区间[l,r],是否存在一个数在[l,r]中出现的次数大于(r-l+1)/2。如果存在,输出这个数,否则输出0。
解题思路
直接上主席树。
构造权值线段树,询问时不停遍历节点数最多的一边就可以了。
但是要注意:最后停下的节点并不是出现次数最多的节点
但对于这道题,如果有解这种方法一定正确。
#include<cstdio>
using namespace std;
const int maxn=500005,maxm=22000005;
inline int _read(){
int num=0;char ch=getchar();
while(ch<'0'||ch>'9') ch=getchar();
while(ch>='0'&&ch<='9') num=num*10+ch-48,ch=getchar();
return num;
}
struct jz{
jz* son[2];
int L,R,x;
};
jz *rt[maxn],t[maxm],*null=t,*len=t;
jz* newnode(int L,int R,int num){
len++;len->L=L,len->R=R;len->x=num;
len->son[0]=len->son[1]=null;
return len;
}
jz* Build(int L,int R){
jz* p=newnode(L,R,0);
if (L==R) return p;
int mid=L+(R-L>>1);
p->son[0]=Build(L,mid);
p->son[1]=Build(mid+1,R);
return p;
}
jz* Insert(jz* k,int x){
jz* p=newnode(k->L,k->R,k->x);
p->son[0]=k->son[0];p->son[1]=k->son[1];
if (p->L==p->R){p->x++;return p;}
int mid=p->L+(p->R-p->L>>1);
if (x<=mid) p->son[0]=Insert(p->son[0],x);
else p->son[1]=Insert(p->son[1],x);
p->x=p->son[0]->x+p->son[1]->x;
return p;
}
int n,m,a[maxn],tot;
int query(jz* k,jz* p,int w){
if (k->L==k->R){if ((k->x-p->x)*2>w) return k->L;else return 0;}
if (k->son[0]->x - p->son[0]->x > k->son[1]->x - p->son[1]->x) return query(k->son[0],p->son[0],w);else query(k->son[1],p->son[1],w);
}
int main(){
freopen("exam.in","r",stdin);
freopen("exam.out","w",stdout);
n=_read();m=_read();
for (int i=1;i<=n;i++) a[i]=_read();
rt[0]=Build(1,n);
for (int i=1;i<=n;i++) rt[i]=Insert(rt[i-1],a[i]);
for (int i=1;i<=m;i++){
int x=_read(),y=_read();
printf("%d\n",query(rt[y],rt[x-1],y-x+1));
}
return 0;
}