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


    题目描述

    墨墨购买了一套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支画笔中共有几种不同颜色的画笔。

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


    先不考虑修改颜色的操作,这个题就是个莫队的板子题。

    然而这题还带修改。带修改的莫队怎么做呢?于是我赶紧去补习了一波。

    对于当前询问,可以知道的是只有它之前的修改操作能够对它造成影响。所以我们可以记录下每个询问的前面有几次修改:

    struct query{
        int l,r,col,pre,id;
    }q[maxm];
    struct change{
        int pos,val;
    }c[maxm];
    
    //main函数中
        for(register int i=1;i<=m;i++){
            cin>>op,l=read(),r=read();
            if(op=='Q'){
                q[++pos_q].l=l,q[pos_q].r=r,q[pos_q].col=l/unit+1;
                q[pos_q].pre=pos_c,q[pos_q].id=pos_q;
            }else c[++pos_c].pos=l,c[pos_c].val=r;
        }
    

    然后我们在莫队的时候加入一个计数的变量:now记录目前做了多少次修改。然后对于当前的第i个询问,设在这个询问之前一共有pre个修改操作,那么会有三种情况:

    1.now<pre。那么把now+1~pre的修改加上去即可。

    2.now=pre,不需要做任何操作。

    3.now>pre。那么把pre+1~now的修改删去即可。

    时间复杂度为O(N^(2/3)),但我并不知道怎么来的

    O3瞩目

    #pragma GCC optimize(3)
    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    #define maxn 50001
    #define maxm 50001
    #define maxcol 1000001
    using namespace std;
    int n,m,col[maxn];
    inline int read(){
        register int x(0),f(1); register char c(getchar());
        while(c<'0'||'9'<c){ if(c=='-') f=-1; c=getchar(); }
        while('0'<=c&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
        return x*f;
    }
    
    struct query{
        int l,r,col,pre,id;
    }q[maxm];
    inline bool cmp(const query &a,const query &b){ return (a.col^b.col)?a.col<b.col:((a.col&1)?a.r>b.r:a.r<b.r); }
    struct change{
        int pos,val;
    }c[maxm];
    int pos_q,pos_c,unit;
    int tot,cnt[maxcol],ans[maxn];
    inline void add(const int &x){ tot+=(++cnt[col[x]]==1); }
    inline void del(const int &x){ tot-=(--cnt[col[x]]==0); }
    inline void Change(const int &now,const int &i){
        if(q[i].l<=c[now].pos&&c[now].pos<=q[i].r){
            tot-=(--cnt[col[c[now].pos]]==0);
            tot+=(++cnt[c[now].val]==1);
        }
        swap(c[now].val,col[c[now].pos]);//用swap就可以把添加和删除询问压在一起
    }
    inline void MoQueue(){
        sort(q+1,q+1+pos_q,cmp);
        int l=1,r=0,now=0;
        for(register int i=1;i<=pos_q;i++){
            while(l<q[i].l) del(l++);
            while(l>q[i].l) add(--l);
            while(r<q[i].r) add(++r);
            while(r>q[i].r) del(r--);
            while(now<q[i].pre) Change(++now,i);
            while(now>q[i].pre) Change(now--,i);
            ans[q[i].id]=tot;
        }
    }
    
    int main(){
        n=read(),m=read(),unit=sqrt(n);
        for(register int i=1;i<=n;i++) col[i]=read();
        char op; int l,r;
        for(register int i=1;i<=m;i++){
            cin>>op,l=read(),r=read();
            if(op=='Q'){
                q[++pos_q].l=l,q[pos_q].r=r,q[pos_q].col=l/unit+1;
                q[pos_q].pre=pos_c,q[pos_q].id=pos_q;
            }else c[++pos_c].pos=l,c[pos_c].val=r;
        }
        MoQueue();
        for(register int i=1;i<=pos_q;i++) printf("%d
    ",ans[i]);
        return 0;
    }
    
  • 相关阅读:
    电容在电路中的作用
    C语言中的弱符号(weak)用法及实例
    一种高灵敏度自带DSP降噪算法的音频采集解决方案
    高灵敏度自带DSP降噪算法的audio codec解决方案
    git clone error: RPC failed; curl 18 transfer closed with outstanding read data remaining
    stm32f103中freertos的tasks基本使用案例及备忘
    移植freertos到stm32 f103 的基本流程和总结
    stm32_f103使用gcc编译的环境下printf打印函数的实现
    C语言中指针和取地址符&的关系
    STM32中ARM系列编译工具链的编译宏选择(__CC_ARM、__ICCARM__、__GNUC__、__TASKING__)
  • 原文地址:https://www.cnblogs.com/akura/p/11069092.html
Copyright © 2020-2023  润新知