P1903 [国家集训队]数颜色 / 维护队列 [带修莫队]

写这篇博客的主要目的是记录 带修莫队 的实现方法.

/数颜色 / 维护队列


Descriptionmathcal{Description}
墨墨购买了一套N支彩色画笔(其中有些颜色可能相同),摆成一排,你需要回答墨墨的提问。墨墨会向你发布如下指令:

1、 Q L R代表询问你从第L支画笔到第R支画笔中共有几种不同颜色的画笔。

2、 R P Col 把第P支画笔替换为颜色Col。

为了满足墨墨的要求,你知道你需要干什么了吗?


正解部分
普通莫队 的分块大小为 Nsqrt N, 按照 为第一关键字, 右端点 为第二关键字排序.

带修莫队 的分块大小为 N23N^{frac{2}{3}},按照 为第一关键字,
右端点 不在同一个块中, 按 右端点为第二关键字 排序, 否则按 操作时间 为第二关键字 排序 .

其余就是莫队基础操作了, 这里不再赘述 .


实现部分
没什么好说的 …

#include <bits/stdc++.h>
const int maxn = 1000005;

int read(){
        int flag = 1;
        char c;
        while (!isdigit(c = getchar())) if(c == '-') flag = -1;
        int sum = 0;
        while(isdigit(c)) sum = sum*10 + c - '0', c = getchar();
        return sum * flag;
}

int N, M, cnt, _cnt, Ans, Tong[maxn], A[maxn], _Ans[maxn];
int block_size;

struct Query{ int L, R, block, index, tim, ans; } Q[maxn];

struct Revise{ int pos, v; } R[maxn];

bool cmp(const Query &a, const Query &b){
        if(a.block != b.block) return a.block < b.block;
        else if(a.R / block_size != b.R / block_size) return a.R < b.R; // WRONG  带修改莫队的理解
        return a.tim < b.tim;
}

bool _cmp(const Query &a, const Query &b){ return a.index < b.index; }  // 没有加取址符号,速度慢

int LL, RR;
void Change(int tim){
        int pos = R[tim].pos, v = R[tim].v;
        if(LL <= pos && pos <= RR){
                Ans -= !-- Tong[A[pos]];
                Ans += !Tong[v] ++;
        }
        R[tim].v ^= A[pos] ^= R[tim].v ^= A[pos];
}

int main(){
        N = read(), M = read();
        block_size = std::pow(N, 2.0/3);
        for(register int i = 1; i <= N; i ++) A[i] = read();
        char s[2];
        for(register int i = 1; i <= M; i ++){ 
                scanf(" %s", s);
                if(s[0] == 'Q'){ 
                        cnt ++;
                        Q[cnt].L = read(), Q[cnt].R = read();
                        Q[cnt].block = Q[cnt].L / block_size + 1;
                        Q[cnt].index = cnt;
                        Q[cnt].tim = _cnt;
                }else if(s[0] == 'R')
                        _cnt++, R[_cnt].pos = read(), R[_cnt].v = read();
        }
        std::sort(Q+1, Q+cnt+1, cmp);
        register int l = 1, r = 0, tim = 0;
        for(register int i = 1; i <= M; i ++){
                LL = Q[i].L;
                RR = Q[i].R;
                while(l < LL) Ans -= !-- Tong[A[l ++]];
                while(l > LL) Ans += !Tong[A[-- l]] ++;
                while(r < RR) Ans += !Tong[A[++ r]] ++;
                while(r > RR) Ans -= !-- Tong[A[r --]];
                while(tim < Q[i].tim) Change(++ tim);
                while(tim > Q[i].tim) Change(tim --);
                Q[i].ans = Ans;
                _Ans[Q[i].index] = Ans;
        }
        //std::cerr << (double)clock() / CLOCKS_PER_SEC << std::endl;
        for(register int i = 1; i <= cnt; i ++) printf("%d
", _Ans[i]);
        return 0;
}
原文地址:https://www.cnblogs.com/zbr162/p/11822567.html