前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >P1903「[国家集训队]数颜色」

P1903「[国家集训队]数颜色」

作者头像
hotarugali
发布2022-03-18 19:51:09
2150
发布2022-03-18 19:51:09
举报

1. 题目

题目链接:P1903「[国家集训队]数颜色」

题目描述

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

  1. Q L R 代表询问你从第 L 支画笔到第 R 支画笔中共有几种不同颜色的画笔。
  2. R P Col 把第 P 支画笔替换为颜色 Col。

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

输入格式

输出格式

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

输入输出样例

输入 #1
代码语言:javascript
复制
6 5
1 2 3 4 5 5
Q 1 4
Q 2 6
R 1 2
Q 1 4
Q 2 6
输出 #1
代码语言:javascript
复制
4
4
3
4

说明/提示

2. 题解

分析

最近在学莫队算法,这是道带修改莫队的板子题。当然有其它更优的方法,但为了巩固最近所学其实是其它更优的方法还没学会,所以这里使用带修改莫队来解决这道题。

  • 首先将所有询问和修改离线存储下来,并根据修改次数记录每个询问的时间轴。
  • 然后对所有询问按照区间左边界 lll 所在块号为第一关键字,区间右边界 rrr 所在块号为第二关键字,时间轴 ttt 所在块号为第三关键字进行排序。
  • 接着维护一个计数数组 countcountcount,记录每种颜色的画笔数量,然后顺序处理每个询问。若当前询问的时间轴大于下一个询问的时间轴,则回滚修改;若当前询问的时间轴小于下一个询问的时间轴,则恢复修改。
  • 最后将答案按原询问顺序依次输出即可。

这里需要注意的是,在进行修改和回滚时,应该使用交换的方式,即将当前值和修改值进行交换,后面回滚时再交换回来。而不能仅仅通过事先维护的两个数组,即修改值数组和备份原值数组,来进行修改和回滚。因为有可能对同一个位置有多个修改,这样在回滚时需要回滚到上一次修改,而非原值。

代码

代码语言:javascript
复制
#include<bits/stdc++.h>
using namespace std;

#ifndef _MOBK_
#define _MOBK_
#define ll long long
#define il inline
#define re register
#define MAXN 2000100

char buf[200];

il ll read_number() {
    ll x = 0;
    char ch = getchar();
    while(ch < '0' || ch > '9'){
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9') {
        x = (x << 3) + (x << 1) + (ch ^ 48);
        ch = getchar();
    }
    return x;
}

il ll read_capital() {
    char ch = getchar();
    while(ch < 'A' || ch > 'Z'){
        ch = getchar();
    }
    return ch;
}

il void write(ll x) {
    ll cnt = 0;
    while(x || !cnt) {
        buf[cnt++] = (x%10) + 48;
        x /= 10;
    }
    while(cnt) {
        putchar(buf[--cnt]);
    }
    putchar('\n');
}

// 分块大小
ll bz;
// 莫队
struct MOBK {
    // 查询区间
    struct Query {
        ll l, r, t, idx;
        bool operator < (const Query q) const {
            return l/bz != q.l/bz ? l < q.l : 
                r/bz != q.r/bz ? r < q.r : t < q.t;
                // (r/bz) & 1 ? t < q.t : t > q.t;
        }
    };
    // 修改记录
    struct Record {
        ll p, v;            // 下标,值
    };
    ll n, m, k;             // 数列长度,查询次数,修改次数
    ll curans;              // 当前查询答案
    ll count[MAXN];         // 计数数组
    ll result[MAXN];        // 答案数组(具体问题具体分析)
    Record modify[MAXN];    // 修改数组
    Query query[MAXN];      // 查询区间数组
    // 初始化
    MOBK() {
        curans = 0;
        memset(count, 0, sizeof(count));
    }
    MOBK(ll _n): n(_n) {
        bz = (ll)pow(n, 2.0/3);
        curans = 0;
        memset(count, 0, sizeof(count));
    }
    // 区间长度增一
    il void add(ll x) {
        curans += count[x] == 0 ? 1 : 0;
        ++count[x];
    }
    // 区间长度减一
    il void del(ll x) {
        --count[x];
        curans -= count[x] == 0 ? 1 : 0;
        
    }
    // 求解答案
    void solver(ll *a) {
        sort(query, query+m);
        re ll l = query[0].l;
        re ll r = query[0].l-1;
        re ll t = 0;
        for(re ll i = 0; i < m; ++i) {
            // printf("(%d,%d,%d)\n", query[i].l, query[i].r, query[i].t);
            while(l < query[i].l) {
                del(a[l++]);
            }
            while(l > query[i].l) {
                add(a[--l]);
            }
            while(r < query[i].r) {
                add(a[++r]);
            }
            while(r > query[i].r) {
                del(a[r--]);
            }
            while(t < query[i].t) {
                if(l <= modify[t].p && modify[t].p <= r) {
                    del(a[modify[t].p]);
                    add(modify[t].v);
                }
                swap(a[modify[t].p], modify[t].v);
                ++t;
            }
            while(t > query[i].t) {
                --t;
                if(l <= modify[t].p && modify[t].p <= r) {
                    del(a[modify[t].p]);
                    add(modify[t].v);
                }
                swap(a[modify[t].p], modify[t].v);
            }
            result[query[i].idx] = curans;
        }
        for(ll i = 0; i < m; ++i) {
            // write(result[i]);
            printf("%lld\n", result[i]);
        }
    }
};
#endif

int main()
{
    char option;
    ll q = 0, r = 0;
    ll n = read_number();
    ll m = read_number();
    static ll a[MAXN] = {0};
    static MOBK mobk = MOBK(n);
    for(re ll i = 0; i < n; ++i) {
        a[i] = read_number();
    }
    for(re ll i = 0; i < m; ++i) {
        option = read_capital();
        if(option == 'Q') {
            mobk.query[q].l = read_number() - 1;
            mobk.query[q].r = read_number() - 1;
            mobk.query[q].t = r;
            mobk.query[q].idx = q;
            ++q;
        } else {
            mobk.modify[r].p = read_number() - 1;
            mobk.modify[r].v = read_number();
            ++r;
        }
    }
    mobk.m = q;
    mobk.k = r;
    mobk.solver(a);
    return 0;
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021-08-27,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 题目
    • 题目描述
      • 输入格式
        • 输出格式
          • 输入输出样例
            • 输入 #1
            • 输出 #1
          • 说明/提示
          • 2. 题解
            • 分析
              • 代码
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档