单点修改莫队 + 离散化 CF

单点修改莫队 + 离散化 CodeForces - 940F【Machine Learning】

https://cn.vjudge.net/contest/304248#problem/F

题意

给定 n 个数和 m 次操作,数组下标 [1, n] ((a_i leq 1e^9)),操作分为两种:

  • 1 x y —— 查询区间 [x, y] 中 集合{(c_0,c_1,c_2,...,c_{10^9})} 的mex,而 (c_i) 表示数值 i 在 [l,r] 中的出现次数,即未出现的最小正整数(次数)。
  • 2 x y —— 将 a[x] 修改成 y

分析

如果不用离散化多好,我就把它加到上一篇博客里去了。

可是我调 BUG 调了快两个小时,TLE 12 不知道见了多少次...

带修改的莫队复杂度为 (O(n^{frac{5}{3}})) 。所以 $$block = (int)pow(n, 2.0/3);$$

切记切记,就因为这块大小把爷整懵逼了。

先使用离散化技巧,把输入数据压缩至 (n+q) 的范围内。

(sum) 数组记录(离散后的)每个数的出现次数,(mark) 数组记录 (sum) 中的数的出现次数。那么题目的询问就转换成:求 (mark) 数组中第一次出现 0 值的位置。

讲道理 mark 数组每次寻找 0 位置肯定需要将近 (O(n)) 的时间吧...所以我不会...

但是,居然不会超过 (O(sqrt{n})) 。因为要将 (mark_1,mark_2,...,mark_k) 填满的话,至少需要 (frac{k(k+1)}{2}) 个元素,由于总长有限,所以可知肯定不会超过 (O(sqrt{n}))因此维护答案的总复杂度也不过 (O(msqrt{n}))

另外,还注意一定要先扩大区间范围,再缩小,防止出现区间 (r < l) 的情况。(这题中可能会导致中间结果多减了,导致 (mark) 数组越界。)

以及时间轴的调整尽量还是放后面比较好...

代码

#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <bitset>
#include <cctype>
#include <cstdio>
#include <vector>
#include <string>
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <iomanip>
#include <numeric>
#include <iostream>
#include <algorithm>
using namespace std;

const int maxn = 1e5+5;

int n, m;
int cur_a[maxn<<1];
int cnt, cnt_;
int a[maxn];
int sum[maxn<<1];
int mark[maxn];
int block;
int ans[maxn];
int belong[maxn];

struct node{
    int l, r, id, t;
    bool operator < (const node &a) const {
        if(belong[l] == belong[a.l] && belong[r] == belong[a.r]) {
            return t < a.t;
        }
        if(belong[l] == belong[a.l]) {
            return r < a.r;
        }
        return l < a.l;
    }
}Q[maxn];

struct Change{
    int x, now, cur;
}C[maxn];

void del(int x) {
    mark[sum[x]] --;
    sum[x] --;
    mark[sum[x]] ++;
}

void add(int x) {
    mark[sum[x]] --;
    sum[x] ++;
    mark[sum[x]] ++;
}

void init() {
    block = (int)pow(n, 2.0/3.0);
    cnt = cnt_ = 0;   
    memset(mark, 0, sizeof(mark));
    memset(sum, 0, sizeof(sum));
}

void dis() {
    for(int i = 1; i <= n; i++) {
        a[i] = cur_a[i];
    }
    sort(cur_a+1, cur_a+1+n+cnt_);
    int tag = unique(cur_a+1, cur_a+1+n+cnt_) - (cur_a+1);
    for(int i = 1; i <= n; i++) {
        a[i] = lower_bound(cur_a+1, cur_a+1+tag, a[i]) - cur_a;
    }
    for(int i = 1; i <= cnt_; i++) {
        C[i].now = lower_bound(cur_a+1, cur_a+1+tag, C[i].now) - cur_a;
        C[i].cur = lower_bound(cur_a+1, cur_a+1+tag, C[i].cur) - cur_a;
    }
    mark[0] = tag + 10;
}

int main() {
    // fopen("in.txt", "r", stdin);
    // fopen("out.txt", "w", stdout);
    while(~scanf("%d%d", &n, &m)) {
        init();
        for(int i = 1; i <= n; i++) {
            scanf("%d", &a[i]);
            cur_a[i] = a[i];
            belong[i] = (i-1)/block + 1;
        }
        int f, x, y;
        for(int i = 1; i <= m; i++) {
            scanf("%d%d%d", &f, &x, &y);
            if(f == 1) {
                Q[++cnt].l = x;
                Q[cnt].r = y;
                Q[cnt].id = cnt;
                Q[cnt].t = cnt_;
            }
            else {
                C[++cnt_].x = x;
                C[cnt_].now = y;
                C[cnt_].cur = a[x];
                a[x] = y;
                cur_a[n+cnt_] = y;
            }
        }
        dis();
        sort(Q+1, Q+1+cnt);
        int l = 1, r = 0;
        int Time = 0;
        for(int i = 1; i <= cnt; i++) {
            while(l > Q[i].l) {
                l--;
                add(a[l]);
            }
            while(r < Q[i].r) {
                r++;
                add(a[r]);
            }       
            while(l < Q[i].l) {
                del(a[l]);
                l++;
            }
            while(r > Q[i].r) {
                del(a[r]);
                r--;
            }
            while(Time < Q[i].t) {
                Time++;
                if(Q[i].l <= C[Time].x && C[Time].x <= Q[i].r) {
                    add(C[Time].now);
                    del(C[Time].cur);
                }
                a[C[Time].x] = C[Time].now;
            }
            while(Time > Q[i].t) {
                if(Q[i].l <= C[Time].x && C[Time].x <= Q[i].r) {
                    add(C[Time].cur);
                    del(C[Time].now);
                }
                a[C[Time].x] = C[Time].cur;
                Time--;
            }
            for(ans[Q[i].id] = 1; mark[ans[Q[i].id]]; ans[Q[i].id]++);
        }
        for(int i = 1; i <= cnt; i++) {
            printf("%d
", ans[i]);
        }
    }
    return 0;
}
原文地址:https://www.cnblogs.com/Decray/p/10947377.html