P3709 莫队

题意

传送门 P3709 大爷的字符串题

题解

求区间内元素最少能组成多少个严格上升子序列,其个数只与相同值的数字有关;即求解区间众数。

使用莫队算法求解。将 a i a_i ai 离散化,维护区间内数字 x x x 的个数 c n t x [ x ] cnt_x[x] cntx[x],以及个数为 k k k 的数字数量 c n t k [ k ] cnt_k[k] cntk[k],即可 O ( 1 ) O(1) O(1) 更新区间出现次数最多的数字的数量。总时间复杂度 O ( N M ) O(N\sqrt M) O(NM )

需要注意,莫队修改左右界时需要保证合理性,故应保证区间修改顺序的合理性,即先拓展区间,再缩减区间。奇偶性排序优化需对应分块的最后一维编号,以保证块的相邻。

实现上,需要注意逻辑运算符的优化,在表达式成立时会导致后几项运算直接被跳过;若将需要执行的自增、自减等运算写入逻辑判断语句,需要注意放在逻辑表达式的第一项。

#include <bits/stdc++.h>
using namespace std;
const int maxn = 200005;
int N, M, X[maxn], xn, xs[maxn];
int res, id[maxn], cnt_x[maxn], cnt_k[maxn], rec[maxn];
struct node
{
    
    
    int l, r, k;
    bool operator<(const node &b) const
    {
    
    
        if (id[l] != id[b.l])
            return l < b.l;
        return (id[l] & 1) ? r < b.r : r > b.r;
    }
} Q[maxn];

inline void add(int i)
{
    
    
    int &k = cnt_x[X[i]];
    if (res == k)
        ++res;
    --cnt_k[k], ++cnt_k[++k];
}

inline void del(int i)
{
    
    
    int &k = cnt_x[X[i]];
    --cnt_k[k];
    if (!cnt_k[k] && res == k)
        --res;
    ++cnt_k[--k];
}

int main()
{
    
    
    scanf("%d%d", &N, &M);
    for (int i = 1; i <= N; ++i)
        scanf("%d", X + i), xs[i] = X[i];
    sort(xs + 1, xs + N + 1);
    xn = unique(xs + 1, xs + N + 1) - (xs + 1);
    for (int i = 1; i <= N; ++i)
        X[i] = lower_bound(xs + 1, xs + xn + 1, X[i]) - xs;
    int w = sqrt(M), t = ceil((double)N / w);
    for (int i = 1; i <= t; ++i)
        for (int l = (i - 1) * w + 1, r = min(i * w, N), j = l; j <= r; ++j)
            id[j] = i;
    for (int i = 1, l, r; i <= M; ++i)
        scanf("%d%d", &l, &r), Q[i] = node{
    
    l, r, i};
    sort(Q + 1, Q + M + 1);
    for (int i = 1, l = Q[1].l, r = l - 1, ql, qr; i <= M; ++i)
    {
    
    
        ql = Q[i].l, qr = Q[i].r;
        while (l > ql)
            add(--l);
        while (r < qr)
            add(++r);
        while (l < ql)
            del(l++);
        while (r > qr)
            del(r--);
        rec[Q[i].k] = -res;
    }
    for (int i = 1; i <= M; ++i)
        printf("%d\n", rec[i]);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/neweryyy/article/details/114463088