1. 程式人生 > >[國家集訓隊]數顏色 / 維護佇列 (帶修改莫隊

[國家集訓隊]數顏色 / 維護佇列 (帶修改莫隊

題目連結

題解

樹套樹做法暫時不會,先坑著

帶修改的莫隊

在普通莫隊基礎上加一個時間量

修改時調整區間,同時調整時間

具體看程式碼

Code

#include<bits/stdc++.h>

#define LL long long
#define RG register

using namespace std;

const int N = 2000010, M = 50010;

int n, m, C[N], belong[N];

struct qus {
    int l, r, id, tim;//tim記錄在這次詢問之前最近它的修改
    bool operator <(qus z) const {
        if (belong[l] == belong[z.l]) {
            if (belong[r] == belong[z.r])
                return tim < z.tim;
            return r < z.r;
        }
        return l < z.l;
    }
}q[M];
struct node {
    int pos, v;
}o[M];

//o記錄修改操作,q記錄詢問
int cnt1, cnt2;

int tot[N], ans, a[M];

inline void del(int c) {if(!(--tot[c])) ans--;}//刪掉
inline void add(int c) {if(++tot[c] == 1) ans++;}//新增
inline void change(int now, int k) {
    if (q[k].l <= o[now].pos && o[now].pos <= q[k].r)
        del(C[o[now].pos]), add(o[now].v);
    swap(C[o[now].pos], o[now].v);//這裡是交換,因為後面撤銷操作需要掉換回來
    return ;
}

inline int gi() {
    RG int x = 0; RG char c = getchar(); bool f = 0;
    while (c != '-' && (c < '0' || c > '9')) c = getchar();
    if (c == '-') c = getchar(), f = 1;
    while (c >= '0' && c <= '9') x = x*10+c-'0', c = getchar();
    return f ? -x : x;
}

int main() {
    int n = gi(), m = gi(), siz = pow(n, 0.666666666666);//siz為塊的大小
    for (RG int i = 1; i <= n; i++) C[i] = gi(), belong[i] = (i-1)/siz+1;
    char type;
    while (m--) {
        scanf("\n%c", &type);
        if (type == 'Q') {
            q[++cnt1].l = gi(); q[cnt1].r = gi(); q[cnt1].id = cnt1; q[cnt1].tim = cnt2;
        }
        else o[++cnt2].pos = gi(), o[cnt2].v = gi();        
    }
    sort(q+1, q+1+cnt1);
    int l = 1, r = 0, now = 0;
    for (int i = 1; i <= cnt1; i++) {
        while (l > q[i].l) add(C[--l]);
        while (l < q[i].l) del(C[l++]);
        while (r < q[i].r) add(C[++r]);
        while (r > q[i].r) del(C[r--]);
        while (now < q[i].tim) change(++now, i);
        while (now > q[i].tim) change(now--, i);
        a[q[i].id] = ans;
    }
    for (int i = 1; i <= cnt1; i++)
        printf("%d\n", a[i]);
    return 0;
}