线段树:
在线段树的每个结点中,用摩尔投票来维护一个区间中的可能的众数,这里需要重载一下线段树中的+操作,对于每次询问,我们可以在logn的时间内找到可能的众数。
此外,我们需要用一个s数组来保存每个元素的下标,因为是顺序遍历arr数组,所以每个元素在s数组中保存的下标一定是递增的。
对于询问query(int l,int r,int threshold),我们先在线段树中找到可能的众数ans,然后在s[ans]上二分查找在[l,r]的区间ans有len个,如果len<threshold,那么说明这个众数不满足要要求,返回-1,否则返回ans。
class MajorityChecker {
struct node{
int l,r;
int val,cnt;
node operator+(const node &p)const{
node res;
if(val==p.val){
res.val=val;
res.cnt=cnt+p.cnt;
}else if(cnt>p.cnt){
res.val=val;
res.cnt=cnt-p.cnt;
}else{
res.val=p.val;
res.cnt=p.cnt-cnt;
}
res.l=min(l,p.l);
res.r=max(r,p.r);
return res;
}
}tr[80010];
int n;
vector<int> a;
vector<int> s[20010];
void build(int u,int l,int r){
tr[u]={l,r};
if(l==r){
tr[u]={l,r,a[l],1};
return;
}
int m=(l+r)>>1;
build(u<<1,l,m);
build(u<<1|1,m+1,r);
tr[u]=tr[u<<1]+tr[u<<1|1];
}
node queryy(int u,int l,int r){
if(l==tr[u].l&&tr[u].r==r) return tr[u];
int m=(tr[u].l+tr[u].r)>>1;
if(r<=m) return queryy(u<<1,l,r);
if(l>m) return queryy(u<<1|1,l,r);
return queryy(u<<1,l,m)+queryy(u<<1|1,m+1,r);
}
public:
MajorityChecker(vector<int>& arr) {
n=arr.size();
a.push_back(-1);
for(int i=0;i<n;i++){
a.push_back(arr[i]);
s[arr[i]].push_back(i+1);
}
build(1,1,n);
}
int query(int left, int right, int threshold) {
int ans=queryy(1,left+1,right+1).val;
int len=upper_bound(s[ans].begin(),s[ans].end(),right+1)-lower_bound(s[ans].begin(),s[ans].end(),left+1);
if(len<threshold) return -1;
return ans;
}
};
时间复杂度:
空间复杂度: