【洛谷】1903:[国家集训队]数颜色 / 维护队列【带修莫队】

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

题目描述

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

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

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

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

输入输出格式

输入格式:

 

第1行两个整数N,M,分别代表初始画笔的数量以及墨墨会做的事情的个数。

第2行N个整数,分别代表初始画笔排中第i支画笔的颜色。

第3行到第2+M行,每行分别代表墨墨会做的一件事情,格式见题干部分。

 

输出格式:

 

对于每一个Query的询问,你需要在对应的行中给出一个数字,代表第L支画笔到第R支画笔中共有几种不同颜色的画笔。

 

输入输出样例

输入样例#1: 复制
6 5
1 2 3 4 5 5
Q 1 4
Q 2 6
R 1 2
Q 1 4
Q 2 6
输出样例#1: 复制
4
4
3
4

说明

对于100%的数据,N≤50000,M≤50000,所有的输入数据中出现的所有整数均大于等于1且不超过10^6。

本题可能轻微卡常数

来源:bzoj2120

本题数据为洛谷自造数据,使用CYaRon耗时5分钟完成数据制作。


Solution

带修莫队模板题。

如何完成有时间线的修改操作??在询问中加一个到它时修改操作到了哪一步的时间线,再像以前一样分块排序。

计算答案时唯一不同的就是当把区间调成当前区间后,要看当前修改到哪一步,如果在它之前,那么就进行修改操作,更新答案。如果在它之后,那么进行撤销修改操作,更新答案。

修改操作中有一步很巧妙,这次修改相当于是把$a[pos]$和当前修改的$col$交换,下次如果有撤销操作,那么就是从$col$修改到$a[pos]$了。

洛谷数据加强后块要弄成$n^{\frac{2}{3}}$才能过叻QAQ太玄学叻....

Code

#include<bits/stdc++.h>
using namespace std;

int n, a[500005], m;
int blo[500005]; 

void read(int &x) {
    x = 0; char ch = getchar();
    while(ch < '0' || ch > '9') ch = getchar();
    while(ch >= '0' && ch <= '9')
      x = x * 10 + ch - '0', ch = getchar();
}

struct Node {
    int l, r, id, ans, pos;
} Q[500005];
bool cmp(Node a, Node b) { 
    if(blo[a.l] != blo[b.l])    return a.l < b.l;
    if(blo[a.r] != blo[b.r])    return a.r < b.r;
    return a.id < b.id;
}
bool cmp2(Node a, Node b) { return a.pos < b.pos; }

struct Edge {
    int pos, to;
} C[500005];

int L, R, cnttot, cnt[1000005];

inline void update(int x) {
    if(C[x].pos >= L && C[x].pos <= R) {
        if(!--cnt[a[C[x].pos]])    -- cnttot;
        if(!cnt[C[x].to] ++) ++ cnttot;
    }
    swap(a[C[x].pos], C[x].to);
}

int main() {
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; i ++)    read(a[i]);
    int bl = pow(n, 0.666666666);
    for(int i = 1; i <= n; i ++)    blo[i] = i / bl + 1;
    int tot = 0, totc = 0;
    scanf("\n");
    for(int i = 1; i <= m; i ++) {
        char opt;
        while(scanf("%c", &opt) == 1) if(opt == 'Q' || opt == 'R')    break;
        if(opt == 'Q') {
            int l, r;
            read(l); read(r);
            Q[++tot].l = l, Q[tot].r = r;
            Q[tot].id = totc, Q[tot].pos = i;
        } else {
            int x, col;
            read(x); read(col);
            ++ totc;
            C[totc].to = col, C[totc].pos = x;
        }
    }
    sort(Q + 1, Q + 1 + tot, cmp);
    int now = 0;
    for(int i = 1; i <= tot; i ++) {
        while(Q[i].l < L) {
            L --;
            if(!cnt[a[L]]++)    cnttot ++;
        }
        while(Q[i].l > L) {
            if(!--cnt[a[L]])    cnttot --;
            L ++;
        }
        while(Q[i].r < R) {
            if(!--cnt[a[R]])    cnttot --;
            R --;
        }
        while(Q[i].r > R) {
            R ++;
            if(!cnt[a[R]]++)    cnttot ++;
        }
        while(now < Q[i].id) update(++now);
        while(now > Q[i].id) update(now--);
        Q[i].ans = cnttot;
    }
    sort(Q + 1, Q + 1 + tot, cmp2);
    for(int i = 1; i <= tot; i ++)
        printf("%d\n", Q[i].ans);
    return 0;
}

 

posted @ 2018-10-12 08:19  Wans_ovo  阅读(355)  评论(0编辑  收藏  举报