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

毒瘤数据卡普通莫队!!

这道题跟普通的莫队题目差不多,但是多了一个修改操作。

所以带修莫队就横空出世了。

普通莫队记录左端点和右端点,那么这里就再记录一个时间轴,表示当时已经执行过几次修改。

之后莫队模板就有六个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;
}

原文地址:https://www.cnblogs.com/Garen-Wang/p/9794919.html

时间: 2024-07-31 13:51:07

P1903 [国家集训队]数颜色 / 维护队列的相关文章

莫队学习总结 &amp;&amp; P1903 [国家集训队]数颜色 / 维护队列

关于时间复杂度 对于多维莫队的复杂度差不多为\(O(n^{\frac{2k-1}{k}})\) 摘自zhihu大佬 奇偶分类优化 return a.l == b.l ? (a.l & 1) ? a.r<b.r: a.r>b.r : a.l < b.l; 这样能快是因为指针移到右边后不用再跳回左边,而跳回左边后处理下一个块又要跳回右边,这样能减少一半操作,理论上能快一倍 思路 好久的题目了,之前其实只会点不修改莫队 对带修改的不大会,也就做过这一个题目 今天重新做了一边,算是有了新

【[国家集训队]数颜色】

下面的同学们搞怪了 好的,话不多说,我来讲这道题时顺便就来讲讲带修莫队 不知道普通莫队是什么的请参见我之前为小Z的袜子写的博客 首先来审审题意:多个区间询问,询问[l,r]中颜色的种类数.可以单点修改颜色. 莫队可以修改??? 那么我们切入正题 这类问题被称为带修莫队(可持久化莫队). 类比到主席树,即可持久化线段树,可以引入一个"修改时间",表示当前询问是发生在前time个修改操作后的.也就是说,在进行莫队算法时,看看当前的询问和时间指针(第三个指针,别忘了s,e)是否相符,然后进行

国家集训队——数颜色

墨墨购买了一套N支彩色画笔(其中有些颜色可能相同),摆成一排,你需要回答墨墨的提问.墨墨会向你发布如下指令: 1. Q L R代表询问你从第L支画笔到第R支画笔中共有几种不同颜色的画笔. 2. R P Col 把第P支画笔替换为颜色Col. 题解: 做这道题之前不会带修改莫队,山神学会了之后手(嘴)把手(嘴)教我打代码. 莫队算法先放下,带修改莫队是酱的:记下所有的修改,同时为每个询问加入一个时间标记,表示这个询问发生时修改到了哪一步.求解之前记录一个时间戳.每次求解一个询问时,先按普通莫队求解

[莫队] 国家集训队 数颜色(尚未完成)

题目描述 墨墨购买了一套N支彩色画笔(其中有些颜色可能相同),摆成一排,你需要回答墨墨的提问.墨墨会向你发布如下指令: 1. Q L R代表询问你从第L支画笔到第R支画笔中共有几种不同颜色的画笔. 2. R P Col 把第P支画笔替换为颜色Col. 为了满足墨墨的要求,你知道你需要干什么了吗? 输入输出格式 输入格式: 第1行两个整数N,M,分别代表初始画笔的数量以及墨墨会做的事情的个数. 第2行N个整数,分别代表初始画笔排中第i支画笔的颜色. 第3行到第2+M行,每行分别代表墨墨会做的一件事

cogs 1901. [国家集训队2011]数颜色

Cogs 1901. [国家集训队2011]数颜色 ★★★   输入文件:nt2011_color.in   输出文件:nt2011_color.out   简单对比时间限制:0.6 s   内存限制:512 MB [试题来源] 2011中国国家集训队命题答辩 [问题描述] 墨墨购买了一套N支彩色画笔(其中有些颜色可能相同),摆成一排,你需要回答墨墨的提问.墨墨会像你发布如下指令:1. Q L R代表询问你从第L支画笔到第R支画笔中共有几种不同颜色的画笔.2. R P Col 把第P支画笔替换为

Bzoj 2453: 维护队列 &amp;&amp; Bzoj 2120: 数颜色 分块,bitset

2453: 维护队列 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 578  Solved: 247[Submit][Status][Discuss] Description 你小时候玩过弹珠吗? 小朋友A有一些弹珠,A喜欢把它们排成队列,从左到右编号为1到N.为了整个队列鲜艳美观,小朋友想知道某一段连续弹珠中,不同颜色的弹珠有多少.当然,A有时候会依据个人喜好,替换队列中某个弹珠的颜色.但是A还没有学过编程,且觉得头脑风暴太浪费脑力了,所以向你

BZOJ 2038: [2009国家集训队]小Z的袜子(hose)

2038: [2009国家集训队]小Z的袜子(hose) Time Limit: 20 Sec  Memory Limit: 259 MBSubmit: 7676  Solved: 3509[Submit][Status][Discuss] Description 作为一个生活散漫的人,小Z每天早上都要耗费很久从一堆五颜六色的袜子中找出一双来穿.终于有一天,小Z再也无法忍受这恼人的找袜子过程,于是他决定听天由命……具体来说,小Z把这N只袜子从1到N编号,然后从编号L到R(L 尽管小Z并不在意两只

BZOJ 2038: [2009国家集训队]小Z的袜子(hose)【莫队算法裸题&amp;&amp;学习笔记】

2038: [2009国家集训队]小Z的袜子(hose) Time Limit: 20 Sec  Memory Limit: 259 MBSubmit: 9894  Solved: 4561[Submit][Status][Discuss] Description 作为一个生活散漫的人,小Z每天早上都要耗费很久从一堆五颜六色的袜子中找出一双来穿.终于有一天,小Z再也无法忍受这恼人的找袜子过程,于是他决定听天由命…… 具体来说,小Z把这N只袜子从1到N编号,然后从编号L到R(L 尽管小Z并不在意两

BZOJ 2038: [2009国家集训队]小Z的袜子(hose) [莫队算法]【学习笔记】

2038: [2009国家集训队]小Z的袜子(hose) Time Limit: 20 Sec  Memory Limit: 259 MBSubmit: 7687  Solved: 3516[Submit][Status][Discuss] Description 作为一个生活散漫的人,小Z每天早上都要耗费很久从一堆五颜六色的袜子中找出一双来穿.终于有一天,小Z再也无法忍受这恼人的找袜子过程,于是他决定听天由命……具体来说,小Z把这N只袜子从1到N编号,然后从编号L到R(L 尽管小Z并不在意两只