1. 程式人生 > >P1903 [國家集訓隊]數顏色 / 維護隊列

P1903 [國家集訓隊]數顏色 / 維護隊列

read 程序 wap tdi 但是 main add 時間排序 sort

毒瘤數據卡普通莫隊!!

這道題跟普通的莫隊題目差不多,但是多了一個修改操作。

所以帶修莫隊就橫空出世了。

普通莫隊記錄左端點和右端點,那麽這裏就再記錄一個時間軸,表示當時已經執行過幾次修改。

之後莫隊模板就有六個while,前四個是一樣的。

最後兩個判斷當前修改次數和目標修改次數的關系。這個就是靈魂了。

重點看這個時間軸上的修改吧。

void change(int idx, int i)
{
    if(q[i].l <= c[idx].p && c[idx].p <= q[i].r)// 當修改點在詢問區間內才需要維護答案
    {
        del(a[c[idx].p]);
        add(c[idx].col);
    }
    std::swap(a[c[idx].p], c[idx].col);// 很巧妙的一個操作,這樣操作答案不變,程序更簡潔
}

完整代碼:

#include<cstdio>
#include<cmath>
#include<algorithm>
const int maxn = 50005;
struct Query
{
    int l, r, id, pre;
} q[maxn];
int q_tot;
struct Change
{
    int p, col;
} c[maxn];
int c_tot;
int belong[maxn], block;
int a[maxn];
int out[maxn];
int n, m;

int l, r, res, changed;
int cnt[1000005];

bool cmp(Query x, Query y)// 按照左右端點所在塊排序,再按時間排序
{
    if(belong[x.l] != belong[y.l]) return belong[x.l] < belong[y.l];
    if(belong[x.r] != belong[y.r]) return belong[x.r] < belong[y.r];
    return x.pre < y.pre;
}
int read()
{
    int ans = 0, s = 1;
    char ch = getchar();
    while(ch > ‘9‘ || ch < ‘0‘){ if(ch == ‘-‘) s = -1; ch = getchar(); }
    while(ch >= ‘0‘ && ch <= ‘9‘) ans = (ans << 3) + (ans << 1) + ch - ‘0‘, ch = getchar();
    return s * ans;
}
void add(int x)
{
    if(++cnt[x] == 1) res++;
}
void del(int x)
{
    if(--cnt[x] == 0) res--;
}
void change(int idx, int i)
{
    if(q[i].l <= c[idx].p && c[idx].p <= q[i].r)
    {
        del(a[c[idx].p]);
        add(c[idx].col);
    }
    std::swap(a[c[idx].p], c[idx].col);
}
void moqueue()
{
    block = pow(n, 0.6666667);// 塊大小要換成這樣
    for(int i = 1; i <= n; i++) belong[i] = (i - 1) / block + 1;
    std::sort(q + 1, q + q_tot + 1, cmp);
    l = 1, r = 0, res = 0, changed = 0;
    for(int i = 1; i <= q_tot; i++)
    {
        while(r < q[i].r) add(a[++r]);
        while(r > q[i].r) del(a[r--]);
        while(l > q[i].l) add(a[--l]);
        while(l < q[i].l) del(a[l++]);
        while(changed < q[i].pre) change(++changed, i);// 改少了
        while(changed > q[i].pre) change(changed--, i);// 改多了
        out[q[i].id] = res;
    }
}
int main()
{
    n = read(), m = read();
    for(int i = 1; i <= n; i++) a[i] = read();
    for(int i = 1; i <= m; i++)
    {
        char opt[3]; scanf("%s", opt);
        if(opt[0] == ‘Q‘)
        {
            int x = read(), y = read();
            q[++q_tot] = (Query){x, y, q_tot, c_tot};
        }
        else if(opt[0] == ‘R‘)
        {
            int p = read(), col = read();
            c[++c_tot] = (Change){p, col};
        }
    }
    moqueue();
    for(int i = 1; i <= q_tot; i++) printf("%d\n", out[i]);
    return 0;
}

P1903 [國家集訓隊]數顏色 / 維護隊列