带修莫队

带修莫队,用于支持单点修改修改的区间查询,块长大小一般n的2/3次方理论最优,排序时先按l,再按r,最后按t升序排列

询问区间内不同颜色数,单点修改成另一颜色

#include<bits/stdc++.h>

using namespace std;

const int N=2e6+6;
int n,m,a[N],bl[N],cnt[N],ans,qc,cc;
struct ask{
    int l,r,t,id,ans;
    inline bool friend operator<(const ask&a,const ask&b){
        return bl[a.l]==bl[b.l]?bl[a.r]==bl[b.r]?a.t<b.t:a.r<b.r:a.l<b.l;
    }
}q[N];
struct change{
    int x,y;
}c[N];
inline void add(int x){
    ans+=++cnt[x]==1;
}
inline void del(int x){
    ans-=--cnt[x]==0;
}
inline void upd(int x,int t){
    if(q[x].l<=c[t].x&&c[t].x<=q[x].r){/*如果修改的值在[l,r]之内,则其变化对答案有影响*/
        del(a[c[t].x]);/*删除该位置上的值*/
        add(c[t].y);/*添加新的值*/
    }
    swap(a[c[t].x],c[t].y);/*无论是否在查询区间内都要交换,使其变成原值或修改后的值*/
}
signed main(){
    ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
    cin>>n>>m;
    int len=pow(n,2.0/3.0);
    for(int i=1;i<=n;i++)cin>>a[i],bl[i]=(i-1)/len+1;
    for(int i=1;i<=m;i++){
        char op[5];
        int l,r;
        cin>>op>>l>>r;
        if(op[0]=='Q')q[++qc]={l,r,cc/*时间,在此之前有几个修改*/,qc/*编号,第几次查询*/};
        else c[++cc]={l,r};
    }
    sort(q+1,q+1+qc);
    for(int i=1,l=1,r=0,t=0;i<=qc;i++){
        while(l>q[i].l)add(a[--l]);
        while(r<q[i].r)add(a[++r]);
        while(l<q[i].l)del(a[l++]);
        while(r>q[i].r)del(a[r--]);
        while(t<q[i].t)upd(i,++t);
        while(t>q[i].t)upd(i,t--);
        q[q[i].id].ans=ans;
    }
    for(int i=1;i<=qc;i++)cout<<q[i].ans<<'\n';
    return 0;
}
posted @ 2022-11-14 17:44  半步蒟蒻  阅读(51)  评论(0)    收藏  举报