Machine Learning CodeForces - 940F(带修改的莫队)

题解原文地址:https://www.cnblogs.com/lujiaju6555/p/8468709.html

给数组a,有两种操作,1 l r查询[l,r]中每个数出现次数的mex,注意是出现次数,mex是最小未出现的自然数,2 x y将a[x]修改为y。

题解:带修改莫队可以解决此题。带修改莫队不会的同学可以先去做下BZOJ2120,然后mex+莫队可以参考BZOJ3585。带修改莫队就是加入了第三关键字time,然后按(左端点所在块,右端点所在块,时间)排序,其中时间指的是在第几次修改操作后。注意修改时要记下原来的数,以便还原回去。维护mex可以对权值分块,如果某块中数的个数==R-L+1,那么这块所有数都出现了,否则暴力扫,我有个同学直接暴力维护也过了。。。

#include <bits/stdc++.h>
#define MOD 2018
#define LL long long
#define ULL unsigned long long
#define Pair pair<int, int>
#define mem(a, b) memset(a, b, sizeof(a))
#define _  ios_base::sync_with_stdio(0),cin.tie(0)
//freopen("1.txt", "r", stdin);
using namespace std;
const int maxn = 200005, INF = 0x7fffffff;
int n, m, pos[maxn], s[maxn], c[maxn], all[maxn], t[maxn], cnt[maxn];
int qsz, csz;
struct node
{
    int l, r, t, res, id;
}Node[maxn];

void add_n(int l, int r, int t, int id)
{
    Node[id].l = l;
    Node[id].r = r;
    Node[id].t = t;
    Node[id].id = id;
}

struct change
{
    int pos, New, Old;
}Cha[maxn];

void add_c(int pos, int New, int Old, int ans)
{
    Cha[ans].pos = pos;
    Cha[ans].New = New;
    Cha[ans].Old = Old;
}

bool cmp(node a, node b)
{
    if(pos[a.l] == pos[b.l])
    {
        if(pos[a.r] == pos[b.r])
            return a.t < b.t;
        return pos[a.r] < pos[b.r];
    }
    return pos[a.l] < pos[b.l];
}

bool cmp_id(node a, node b)
{
    return a.id < b.id;
}

int update(int val, int d)
{
    if(s[val] > 0) cnt[s[val]]--;    //s是记录val 出现的次数  cnt标记这个次数是否出现  因为有多个数 可能有些数出现的次数相同 所有用++即可
    s[val] += d;                     //因为当前数val的次数改变 所以 如果未改变时的val的次数 给cnt贡献了1个的话 要先减去 再更新s[val] 再更新cnt[s[val]]
    if(s[val] > 0) cnt[s[val]]++;
}
int L=1, R=0, T=0;
int go(int idx, int val)
{
    if(L <= idx && idx <= R)  //如果 当前时间内 修改的位置在当前区间 则先删去上一次在这个位置更新的值 再加上本次在这个位置更新的值
    {
        update(c[idx], -1);
        update(val, 1);
    }
    c[idx] = val;     //更新
}


int main()
{
    qsz = csz = 0;
    int tot = 0;
    scanf("%d%d", &n, &m);
    for(int i=1; i<=n; i++)
    {
        scanf("%d",&c[i]);
        t[i] = c[i];
        all[++tot] = c[i];
    }
    int block=pow(n,2.0/3);
    for(int i=1; i<=n; i++)
        pos[i] = (i-1)/block + 1;
    for(int i=1; i<=m; i++)
    {
        int op, l, r;
        scanf("%d%d%d", &op, &l, &r);
        if(op == 1)
        {
            add_n(l, r, csz, ++qsz);
        }
        else
        {
            add_c(l, r, t[l], ++csz);
            t[l] = r;
            all[++tot] = r;
        }
    }
    sort(all+1, all+tot+1);
    tot = unique(all+1, all+tot+1) - (all + 1);
    for(int i=1; i<=n; i++)
        c[i] = lower_bound(all+1, all+tot+1, c[i]) - all;
    for(int i=1; i<=csz; i++)
    {
        Cha[i].New = lower_bound(all+1, all+tot+1, Cha[i].New) - all;
        Cha[i].Old = lower_bound(all+1, all+tot+1, Cha[i].Old) - all;
    }
    sort(Node+1, Node+qsz+1, cmp);
    for(int i=1; i<=qsz; i++)
    {
//        for(; T < Node[i].t; T++)
//            go(Cha[T+1].pos, Cha[T+1].New);
//        for(; T > Node[i].t; T--)
//            go(Cha[T].pos, Cha[T].Old);
        for(; R < Node[i].r; R++)
            update(c[R+1], 1);
        for(; R > Node[i].r; R--)
            update(c[R], -1);
        for(; L < Node[i].l; L++)
            update(c[L], -1);
        for(; L > Node[i].l; L--)
            update(c[L-1], 1);
        for(; T < Node[i].t; T++)       //遍历在询问当前区间时 的 时间之前的修改
            go(Cha[T+1].pos, Cha[T+1].New);
        for(; T > Node[i].t; T--)
            go(Cha[T].pos, Cha[T].Old);

        for(int j=1; ; j++)
            if(!cnt[j])
            {
                Node[i].res = j;
                break;
            }
     //   cout<< Node[i].res <<endl;
    }
    sort(Node+1, Node+qsz+1, cmp_id);
    for(int i=1; i<=qsz; i++)
        cout<< Node[i].res <<endl;

    return 0;
}

猜你喜欢

转载自www.cnblogs.com/WTSRUVF/p/9346960.html