[国家集训队]数颜色 / 维护队列 (带修莫队模板题)

Posted 昵称很长很长真是太好了

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[国家集训队]数颜色 / 维护队列 (带修莫队模板题)相关的知识,希望对你有一定的参考价值。

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

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

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

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

思路:
如果没有修改的话,那么就可以用莫队很轻松的做出来(或者是主席树)。
但是带了修改我们该怎么办呢,带修莫队或者(树套树)。

空间时间
树套树 O ( n l o g n 2 ) O(nlogn^2) O(nlogn2) O ( n l o g n 2 ) O(nlogn^2) O(nlogn2)
带修莫队 O ( n ) O(n) O(n) n 5 / 3 n^{5/3} n5/3

具体可以根据题目来选择。
带修莫队块的大小为pow(2/3)时,世家复杂度时最优秀的,具体的证明:戳我
与普通莫队不同的是,加了一维时间轴。

在修改时:
1.若修改的位置在当前区间内,需要更新答案(sub原颜色,add修改后的颜色)。
2.无论修改的位置是否在当前区间内,都要进行修改(以供add和sub函数在以后更新答案)。

代码:

//#pragma GCC optimize(2)
#include<bits/stdc++.h>

#define endl '\\n'
//#define ll long long
//#define int long long
using namespace std;
const int maxn=2e5+10;


int a[maxn];

struct node{
    int l,r,t,id;
}q[maxn];
pair<int,int> c[maxn];
int cntq,cntc;
int be[maxn],sz;

struct rule{
    bool operator ()(const node & x,const node & y)const{
        if(be[x.l]!=be[y.l])return x.l<y.l;
        if(be[x.r]!=be[y.r])return x.r<y.r;
        return x.t<y.t;
    }
};

int cnt[1000010];
int sum,ans[maxn];
int l=0,r=0,t=0;

void add(int x){
    if(++cnt[a[x]]==1) sum++;
}

void sub(int x){
    if(--cnt[a[x]]==0) sum--;
}
void upt(int x){
    if(c[x].first>=l&&c[x].first<=r){
        if(--cnt[a[c[x].first]]==0) sum--;
        if(++cnt[c[x].second]==1) sum++;
    }
    swap(c[x].second,a[c[x].first]);
}

signed main(){
    int n,m;
    cin>>n>>m;
    sz=pow(n,2.0/3.0);
    for(int i=1;i<=n;i++){
        cin>>a[i];
        be[i]=i/sz+1;
    }
    for(int i=1;i<=m;i++){
        char opt;
        int x,y;
        cin>>opt>>x>>y;
        if(opt=='Q'){
            q[++cntq].l=x;
            q[cntq].r=y;
            q[cntq].id=cntq;
            q[cntq].t=cntc;
        }
        else{
            c[++cntc].first=x;
            c[cntc].second=y;
        }
    }
    sort(q+1,q+cntq+1,rule());

    for(int i=1;i<=cntq;i++){
        while(r<q[i].r) add(++r);
        while(l>q[i].l) add(--l);
        while(r>q[i].r) sub(r--);
        while(l<q[i].l) sub(l++);

        while(t<q[i].t) upt(++t);
        while(t>q[i].t) upt(t--);

        ans[q[i].id]=sum;

    }
    for(int i=1;i<=cntq;i++) cout<<ans[i]<<endl;

}

以上是关于[国家集训队]数颜色 / 维护队列 (带修莫队模板题)的主要内容,如果未能解决你的问题,请参考以下文章

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

bzoj 2120 数颜色 (带修莫队)

数颜色(带修莫队模板)

bzoj 2453 : 维护队列 带修莫队

[国家集训队]数颜色

2120: 数颜色(带修莫队)