莫队维护区间众数出现次数

传送门:

这个莫队是求的众数出现的次数,不能求出那个众数是那个数

题意:

给定数组a长度为n,q次询问,
每次询问给定L,R,你可以将[L,R]中的数放进若干个盒子,
要求满足每盒子中的众数出现次数<=(盒子中数总数+1)/2,
问最少需要多少个盒子。

数据范围:n,q<=3e5,a(i)<=n

设[l,r]的长度为len,众数个数为cnt,那么非众数个数x=len-cnt.

x个非众数可以和x+1个众数放在一起,满足条件,
多出来的众数只能一个一个放了,个数为cnt-(x+1).

因此需要的总个数为cnt-(len-cnt+1)+1=cnt*2-len.

  

void add(int pos){
    sum[z[a[pos]]]--;//3变4了 
    z[a[pos]]++;
    sum[z[a[pos]]]++;
    ans=max(ans,z[a[pos]]);
}
void remove(int pos){
    sum[z[a[pos]]]--;
    if(z[a[pos]]==ans&&sum[z[a[pos]]]==0) ans--;
    z[a[pos]]--;
    sum[z[a[pos]]]++;
}

 

重点就是怎么维护这个众数出现的次数,就是你先有一个数组z[i]来维护a[i]出现的次数,

然后再用一个数组sum[i]代表的是z[i]出现次数,例如:

sum[z[5]]--;

z[5]++;

sum[z[5]]++;这是加的操作

加入次数5为出现最多的数出现了4次,马上要减少1次

sum[5]--;

当出现5次的为0的时候那么就是就是没有出现5次的数了,然后ans--

为什么这样呢?

就是一个区间内出现次数最多的数可能出现多次,所以你不能直接ans--

#include<iostream>
#include<algorithm>
#include<math.h> 
using namespace std;
typedef long long ll;
const int maxn=5e6+100;
inline ll read() {
  ll x = 0;
  bool f = 0;
  char ch = getchar();
  while (ch < '0' || '9' < ch) f |= ch == '-', ch = getchar();
  while ('0' <= ch && ch <= '9') x = x * 10 + ch - '0', ch = getchar();
  return f ? -x : x;
}
int belong[maxn],res[maxn];
int a[maxn];
int z[maxn];
int sum[maxn];
int block;
struct node{
    int l,r,id;
}q[maxn];
bool cmp(node x,node y){
    if(belong[x.l]!=belong[y.l]){
        return x.l<y.l;
    }
    else{
        if(belong[x.l]&1){
            return x.r<y.r;
        }
        else{
            return x.r>y.r;
        }
    }
}
int ans=0;
void add(int pos){
    sum[z[a[pos]]]--;//3变4了 
    z[a[pos]]++;
    sum[z[a[pos]]]++;
    ans=max(ans,z[a[pos]]);
}
void remove(int pos){
    sum[z[a[pos]]]--;
    if(z[a[pos]]==ans&&sum[z[a[pos]]]==0) ans--;
    z[a[pos]]--;
    sum[z[a[pos]]]++;
}
int main(){
    int n,m;
    n=read();
    m=read(); 
    block=sqrt(n);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        belong[i]=(i-1)/block+1;
    } 
    for(int i=1;i<=m;i++){
        q[i].l=read(); 
        q[i].r=read();
        q[i].id=i;
    }
    sort(q+1,q+m+1,cmp);
    int l=1,r=0;
    int len;
    for(int i=1;i<=m;i++){
        int ql=q[i].l,qr=q[i].r;
        while(l<ql){
            remove(l++);
        }    
        while(l>ql){
            add(--l);
        } 
        while(r>qr){
            remove(r--);
        } 
        while(r<qr){
            add(++r);
        }
        len=(qr-ql+1);
        res[q[i].id]=max(1,2*ans-len);
    }
    for(int i=1;i<=m;i++){
        printf("%d\n",res[i]);
    }
} 

 主席树不会:

大佬的博客

posted @ 2021-04-23 20:41  lipu123  阅读(351)  评论(0)    收藏  举报