大爷的字符串题 [莫队]

大爷的字符串题

题目描述见链接 .


color{red}{正解部分}

题意: 求区间内出现最多的数字出现的次数 .

使用 莫队, 记 Tong[x]Tong[x] 表示 xx 出现了几次, 再记 num[x]num[x] 表示出现 xx 次的数字有多少个,
Max_numMax\_num 表示答案,

  • 添加 xx, 若 ++Tong[x]++ Tong[x]Max_numMax\_num 大, 则更新 Max_numMax\_num .
  • 删除 xx, 若 num[Tong[x]]=0-- num[Tong[x]] = 0, 且 Tong[x]=Max_numTong[x] = Max\_num, 则说明修改前 xx 是出现次数最多的唯一数字, 修改后就不存在出现 Tong[x]Tong[x] 次的数字了, 答案变为 Tong[x]1Tong[x]-1 .

color{red}{实现部分}

放上很久以前写的代码 …

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cmath>
#define _for(x, N, p) for(int i = x; i <= N; i += p)

const int maxn = 200005;

int N, M, Ans;
int Tong[maxn], num[maxn], A[maxn], B[maxn];
int Max_num, Max_index;

struct Query{ int L, R, block, index, Ans; } Q[maxn];

bool cmp(const Query &a, const Query &b){ return a.block==b.block?a.R<b.R:a.block<b.block; }
bool _cmp(const Query &a, const Query &b){ return a.index < b.index; }

void Add(int x){ 
    num[Tong[x]] --;
    Tong[x] ++;
    num[Tong[x]] ++;
    if (Max_num < Tong[x]) Max_num ++;
}

void Del(int x){ 
    num[Tong[x]] --;
    Tong[x] --;
    num[Tong[x]] ++;
    if (num[Max_num] == 0) Max_num --;
}

int main(){
    scanf("%d %d", &N, &M); 
    int block_size = std::sqrt(N);
    _for(1, N, 1) scanf("%d", &A[i]), B[i] = A[i];
    std::sort(B+1, B+N+1);
    int size = std::unique(B, B+N+1) - B;
    _for(1, N, 1) A[i] = std::lower_bound(B+1, B+size+1, A[i]) - B;
    _for(1, M, 1){
        scanf("%d %d", &Q[i].L, &Q[i].R);
        Q[i].block = Q[i].L / block_size + 1;
        Q[i].index = i;
    }
    std::sort(Q+1, Q+M+1, cmp);
    int l = 1, r = 0;
    _for(1, M, 1){
        while(l < Q[i].L) Del(A[l ++]);
        while(l > Q[i].L) Add(A[-- l]);
        while(r < Q[i].R) Add(A[++ r]);
        while(r > Q[i].R) Del(A[r --]);
        Q[i].Ans = Max_num;
    }
    std::sort(Q+1, Q+M+1, _cmp);
    _for(1, M, 1) printf("-%d
", Q[i].Ans);
    return 0;
}
原文地址:https://www.cnblogs.com/zbr162/p/11822431.html