传送门

安利一下既好写又美观的树套树(大雾

思路和HH的项链一样,维护每个位置下一个和它相同颜色的位置$nex[i]$,查询时就找$nex[i]>R$且$L\le i\le R$的个数($[L,R]$为待查询区间,下同)。

两个限制条件自然想到树套树。外层用线段树或树状数组维护$nex[i]$,每个节点内部开一个平衡树或动态开点线段树维护位置。查询时直接查外层$[R+1,n+1]$(这里提前把$nex[i]$为$0$的都改为$n+1$)中,内层位于$[L,R]$的数量。

不过修改比较麻烦:

记$i$为修改点,$last$为上一个和$i$颜色相同的位置(可以开数组记下来,想偷懒的话直接开平衡树查也行),$j$为$i$前面第一个颜色为要修改的颜色的位置,二元组$(x,y)$为外层为$x$,内层为$y$。修改操作就为:

  • 删除$(i,last)$
  • 插入$(nex[i],last)$
  • 赋值$nex[last]=nex[i]$
  • 删除$(nex[i],i)$
  • 插入$(nex[j],i)$
  • 删除$(nex[j],j)$
  • 插入$(i,j)$
  • 赋值$nex[i]=nex[j],nex[j]=i$

不理解的话可以画个图,观察一下一次修改操作会对$last,nex[i],j,nex[j]$产生的影响。

因为有可能$j$或$last$为$0$,需要记一下每种颜色当前第一次出现的位置,判断修改。

线段树套线段树$2900ms$($O_2$),树状数组套线段树$1300ms$($O_2$)

代码:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>

#define maxn 50005
#define inf 0x3f3f3f3f

using namespace std;

inline int read(){
    int x=0,y=0;
    char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')y=1;ch=getchar();}
    while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    return y?-x:x;
}
template<typename T>
inline T read(){
    T x=0;
    int y=0;
    char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')y=1;ch=getchar();}
    while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    return y?-x:x;
}
inline int ran(){
    static int seed=45562;
    return seed=(seed*48271LL%2147483647);
}
int n;
#define ls(x) ls[x]
#define rs(x) rs[x]
struct Treap{
    int dat[maxn<<2],ls[maxn<<2],rs[maxn<<2],siz[maxn<<2],ra[maxn<<2],cnt;
    inline void update(int node){
        siz[node]=siz[ls(node)]+siz[rs(node)]+1;
    }
    void right(int &node){
        int rec=ls(node);
        ls(node)=rs(rec);
        rs(rec)=node;
        node=rec;
        update(rs(node)),update(node);
    }
    void left(int &node){
        int rec=rs(node);
        rs(node)=ls(rec);
        ls(rec)=node;
        node=rec;
        update(ls(node)),update(node);
    }
    void insert(int &node,int d){
        if(!node){
            node=++cnt;
            ra[node]=ran(),dat[node]=d,siz[node]=1;
            return;
        }
        if(dat[node]<d){
            insert(rs(node),d);
            if(ra[rs(node)]>ra[node])left(node);
        }
        else {
            insert(ls(node),d);
            if(ra[ls(node)]>ra[node])right(node);
        }
        ++siz[node];
    }
    void del(int &node,int d){
        if(dat[node]==d){
            if(ls(node)&&rs(node)){
                if(ra[ls(node)]>ra[rs(node)])right(node),del(rs(node),d);
                else left(node),del(ls(node),d);
                --siz[node];
            }
            else node=ls(node)|rs(node);
            return;
        }
        if(dat[node]<d)del(rs(node),d);
        else del(ls(node),d);
        --siz[node];
    }
    int getpre(int node,int d){
        int ans=0;
        while(node){
            if(dat[node]<d)ans=max(ans,dat[node]),node=rs(node);
            else node=ls(node);
        }
        return ans;
    }
}tr;
struct Data_Segment_Tree{
    int ls[maxn<<5],rs[maxn<<5],sum[maxn<<5],cnt;
    void add(int poi,int l,int r,int &node,int d){
        if(!node)node=++cnt;
        sum[node]+=d;
        if(l==r)return;
        int mid=l+r>>1;
        if(poi<=mid)add(poi,l,mid,ls(node),d);
        else add(poi,mid+1,r,rs(node),d);
    }
    int ask(int L,int R,int l,int r,int node){
        if(!node)return 0;
        if(L<=l&&R>=r)return sum[node];
        int mid=l+r>>1,ans=0;
        if(L<=mid)ans=ask(L,R,l,mid,ls(node));
        if(R>mid)ans+=ask(L,R,mid+1,r,rs(node));
        return ans;
    }
}dst;
#undef ls
#undef rs
/*==============树状数组套线段树===============*/
struct Binary_Indexed_Tree{
    int root[maxn];
#define lowb(x) (x&-x)
    inline void add(int x,int pl,int d){
        while(x<=n+1)dst.add(pl,1,n,root[x],d),x+=lowb(x);
    }
    inline int ask(int x,int l,int r){
        int ans=0;
        while(x)ans+=dst.ask(l,r,1,n,root[x]),x-=lowb(x);
        return ans;
    }
}bit;
int root[1000005],fir[1000005],nex[maxn],pre[1000005],a[maxn];
inline void change(int i,int d){
    if(a[i]==d)return;
    int last=tr.getpre(root[a[i]],i),j=tr.getpre(root[d],i);
    if(fir[a[i]]==i)fir[a[i]]=nex[i];
    if(last){
        bit.add(i,last,-1);
        bit.add(nex[i],last,1);
        nex[last]=nex[i];
    }
    bit.add(nex[i],i,-1);
    if(j){
        bit.add(nex[j],i,1);
        bit.add(nex[j],j,-1);
        bit.add(i,j,1);
        nex[i]=nex[j];
        nex[j]=i;
    }
    else {
        bit.add(fir[d],i,1);
        nex[i]=fir[d],fir[d]=i;
    }
    tr.del(root[a[i]],i),tr.insert(root[d],i);
    a[i]=d;
}
/*==================End====================*/
/*=========================================*/
/*==============线段树套线段树===============*/
#define ls(x) x<<1
#define rs(x) x<<1|1
struct Next_Segment_Tree{
    int root[maxn<<2];
    void add(int poi,int l,int r,int node,int pl,int d){
        dst.add(pl,1,n,root[node],d);
        if(l==r)return;
        int mid=l+r>>1;
        if(poi<=mid)add(poi,l,mid,ls(node),pl,d);
        else add(poi,mid+1,r,rs(node),pl,d);
    }
    int ask(int L,int l,int r,int node,int ll,int rr){
        if(L<=l)return dst.ask(ll,rr,1,n,root[node]);
        int mid=l+r>>1;
        return (L<=mid?ask(L,l,mid,ls(node),ll,rr):0)+ask(L,mid+1,r,rs(node),ll,rr);
    }
}nst;
int root[1000005],fir[1000005],nex[maxn],pre[1000005],a[maxn];
inline void change(int i,int d){
    if(a[i]==d)return;
    int last=tr.getpre(root[a[i]],i),j=tr.getpre(root[d],i);
    if(fir[a[i]]==i)fir[a[i]]=nex[i];
    if(last){
        nst.add(i,1,n+1,1,last,-1);
        nst.add(nex[i],1,n+1,1,last,1);
        nex[last]=nex[i];
    }
    nst.add(nex[i],1,n+1,1,i,-1);
    if(j){
        nst.add(nex[j],1,n+1,1,i,1);
        nst.add(nex[j],1,n+1,1,j,-1);
        nst.add(i,1,n+1,1,j,1);
        nex[i]=nex[j];
        nex[j]=i;
    }
    else {
        nst.add(fir[d],1,n+1,1,i,1);
        nex[i]=fir[d],fir[d]=i;
    }
    tr.del(root[a[i]],i),tr.insert(root[d],i);
    a[i]=d;
}
/*==============End===============*/
int main(){
    n=read();
    int m=read();
    for(register int i=1;i<=n;++i){
        a[i]=read(),nex[pre[a[i]]]=i,pre[a[i]]=i;
        if(!fir[a[i]])fir[a[i]]=i;
        tr.insert(root[a[i]],i);
    }
    for(register int i=1;i<=n;++i){
        if(!nex[i])nex[i]=n+1;
        bit.add(nex[i],i,1);
    }
    for(register int i=1;i<=1000000;++i)
        if(!fir[i])fir[i]=n+1;
    char s[2];
    int l,r;
    while(m--){
        scanf("%s",s);
        if(s[0]=='Q')l=read(),r=read(),printf("%d\n",bit.ask(n+1,l,r)-bit.ask(r,l,r));
        else l=read(),r=read(),change(l,r);
    }
}