【Ynoi2010】Brodal queue

分块。

题目大意:

给定一个数列 $a_1,a_2,a_3,\ldots,a_n$,有两种操作:

  1. 给定 $l,r,x$,把 $a_{l..r}$ 改为 $x$。
  2. 给定 $l,r$,问有多少数对 $i,j$ 满足 $a_i=a_j$ 且 $l\leq i\lt j\leq r$。

题解:

序列分块。

分块,维护每种数的前缀出现次数,以及每种数的前缀出现次数的平方。

我们需要计算一段区间的每种数的出现次数的平方的和,考虑记录前缀的平方和,使用 $(a-b)^2=a^2-2ab+b^2$ 计算。

维护 $f(i,j)$ 表示 $\sum_x cnt(x,i)\cdot cnt(x,j)$。其中 $cnt(x,k)$ 表示颜色 $x$ 在前 $k$ 个块中的出现次数。

对 $f(i,j)$ 的修改,考虑块 $k$ 处的修改,设这种颜色在前 $i$ 块和前 $j$ 块中的出现次数为 $a,b$,在 块 $k$ 中的出现次数增加了 $x$。

对于 $i\leq k,k\leq j$ 的,他们的变化为 $a(b+x)-ab=ax$。我们对每个左端点为 $i$ 的 $f(i,\texttt*)$ 都记录变化量。

对于 $i<k,j<k$ 的,变化为 $0$。

对于 $k<i,k\leq j$ 的,变化为 $(a+x)(b+x)-ab=ax+bx+x^2$。我们对每个左端点为 $i$ 的 $f(i,\texttt{*})$ 都记录变化量 $ax$,对每个右端点为 $i$ 的 $f(\texttt{*},i)$ 都记录变化量 $bx+x^2$。

这部分可以使用差分的技巧做到 $O(1)$ 修改 $O(\sqrt n)$ 查询。

那么块 $i$ 与 $j$ 之间的所有数的出现次数的平方和,我们只需要知道前 $i$ 个块的平方和,前 $j$ 个块的平方和,$f(i,j)$ 的值,就可以求得。计算的复杂度为 $O(\sqrt n)$。

关于修改操作,边角暴力,中间的如果只有一个数则 $O(1)$ 修改,这会给这个块产生 $O(1)$ 个额外颜色段,否则 $O(\sqrt n)$ 删除块中的段贡献,总产生的颜色数为 $O(n+m)$。此时更新 $f$ 的复杂度为 $O((n+m)\sqrt n)$。

然后对于一个块,如果只有一种颜色,我们不把他计算到 $f$ 中而是在查询的时候计算这个块的贡献。

那么需要计算进 $f$ 的颜色段个数是 $O(n+m)$,所以每次对颜色段进行重新计算前缀信息,时间复杂度 $O((n+m)\sqrt n)$。

总时间复杂度 $O((n+m)\sqrt n)$,空间复杂度 $O(n \sqrt n)$。

Code:

#include<cstdio>
#include<cstring>
#include<cctype>
#define bel(x)(((x-1)/B)+1)
typedef unsigned long long LL;
const int B=1200,N=2e5+5,K=N/B+2,BK=B+2,__=B*(B-1)/2;
char*ss;
struct istream {
    static const int size = 1 << 25;
    char buf[size], *vin;
    inline istream() {
        fread(buf,1,size,stdin);
        vin = buf - 1;
    }
    inline istream& operator >> (int & x) {
        for(;isspace(*++vin););
        for(x = *vin & 15;isdigit(*++vin);) x = x * 10 + (*vin & 15);
        return * this;
    }
} cin;
struct ostream {
    static const int size = 1 << 22;
    char buf[size], *vout;
    unsigned map[10000];
    inline ostream() {
        for(int i = 0;i < 10000;++i)
        map[i] = i % 10 + 48 << 24 | i / 10 % 10 + 48 << 16 | i / 100 % 10 + 48 << 8 | i / 1000 + 48;
        vout = buf + size;
    }
    inline ~ ostream()
    { fwrite(vout,1,buf + size - vout,stdout); }
    inline ostream& operator << (unsigned long long x) {
        for(;x >= 10000;x /= 10000) *--(unsigned*&)vout = map[x % 10000];
        do *--vout = x % 10 + 48; while(x /= 10);
        return * this;
    }
    inline ostream& operator << (char x) {
        *--vout = x;
        return * this;
    }
}cout;
int pre[N][K],a[N],n,m,blocks,L[K],R[K],dt[N];
int tag[K];
LL sum[K],f[K][K];
unsigned long long _s[N];
LL A1[K][K],A2[K][K];
int sta[BK*3],top;
inline LL sqr(int x){return(LL)x*x;}
void init(){
    static bool vis[N];
    blocks=bel(n);
    for(int i=1;i<=blocks;++i)L[i]=R[i-1]+1,R[i]=i*B;R[blocks]=n;
    for(int i=1;i<=blocks;++i){
        for(int j=1;j<=n;++j)pre[j][i]=pre[j][i-1];
        top=0;
        for(int j=L[i];j<=R[i];++j){
            const int&x=a[j];
            ++pre[x][i];
            if(!vis[x])vis[x]=1,sta[++top]=x;
        }
        sum[i]=sum[i-1];
        for(int j=1;j<=top;++j)
        sum[i]+=sqr(pre[sta[j]][i])-sqr(pre[sta[j]][i-1]);
        for(int j=1;j<=n;++j)
        f[i][i]+=(LL)pre[j][i-1]*pre[j][i];
        for(int p=1;p<i;++p){
            LL&s=f[p][i];
            s=f[p][i-1];
            for(int j=1;j<=top;++j)
            s+=(LL)pre[sta[j]][p-1]*(pre[sta[j]][i]-pre[sta[j]][i-1]);
        }
        for(int j=1;j<=top;++j)vis[sta[j]]=0;
    }
}
inline void Modify_color(int dlt,int id,int x){
    int*P=pre[x];
    for(int i=1;i<=blocks;++i)A1[id][i]+=(LL)dlt*P[i-1];
    for(int i=id;i<=blocks;++i)A2[id][i]+=(LL)dlt*(P[i]+dlt),sum[i]+=sqr(P[i]+dlt)-sqr(P[i]),P[i]+=dlt;
}
inline void modify_all(int id,int x){
    if(!tag[id]){
        top=0;
        for(int i=L[id];i<=R[id];++i)
        if(!dt[a[i]]++)sta[++top]=a[i];
        for(int i=1;i<=top;++i)Modify_color(-dt[sta[i]],id,sta[i]),dt[sta[i]]=0;;
    }
    tag[id]=x;
}
void modify(int l,int r,int x){
    const int id=bel(l);
    if(tag[id]){
        for(int i=L[id];i<=R[id];++i)a[i]=tag[id];
        Modify_color(R[id]-L[id]-r+l,id,tag[id]);
        Modify_color(r-l+1,id,x);
        tag[id]=0;
        for(int i=l;i<=r;++i)a[i]=x;
    }else{
        top=0;
        for(int i=l;i<=r;++i){
            if(!dt[a[i]]++)sta[++top]=a[i];
            a[i]=x;
        }
        for(int i=1;i<=top;++i)Modify_color(-dt[sta[i]],id,sta[i]);
        Modify_color(r-l+1,id,x);
        for(int i=1;i<=top;++i)dt[sta[i]]=0;
    }
}
inline int get(int x){return tag[bel(x)]?tag[bel(x)]:a[x];}
int solve(int l,int r){
    int ret=0;
    for(int i=l;i<=r;++i)ret+=dt[get(i)]++;
    for(int i=l;i<=r;++i)dt[get(i)]=0;
    return ret;
}
LL F(int l,int r){
    LL ret=f[l][r];
    for(int i=1;i<=r;++i)ret+=A1[i][l];
    for(int i=1;i<l;++i)ret+=A2[i][r];
    return ret;
}
int main(){
    cin>>n>>m;
    for(int i=1;i<=n;++i)cin>>a[i];
    init();
    unsigned lst=0;
    for(int T=1;T<=m;++T){
        int op,l,r;
        cin>>op>>l>>r;
        l^=lst,r^=lst;
        if(op==1){
            _s[T]=~0;
            int x;
            cin>>x;
            x^=lst;
            const int bL=bel(l),bR=bel(r);
            if(bL==bR)modify(l,r,x);else{
                modify(l,R[bL],x),modify(L[bR],r,x);
                for(int i=bL+1;i<bR;++i)
                modify_all(i,x);
            }
        }else{
            LL ans=0;
            if(r-l+1<=3*B)ans=solve(l,r);else{
                const int bL=bel(l),bR=bel(r);
                ans=sum[bR-1]+sum[bL]-2*F(bL+1,bR-1);
                for(int i=bL+1;i<bR;++i)ans-=!tag[i]*B;
                ans>>=1,top=0;
                for(int i=R[bL];i>=l;--i){
                    const int x=get(i);
                    if(!dt[x])sta[++top]=x;
                    ++dt[x];
                }
                for(int i=L[bR];i<=r;++i){
                    const int x=get(i);
                    if(!dt[x])sta[++top]=x;
                    ++dt[x];
                }
                for(int i=1;i<=top;++i)
                ans+=(LL)dt[sta[i]]*(pre[sta[i]][bR-1]-pre[sta[i]][bL])+(LL)dt[sta[i]]*(dt[sta[i]]-1)/2;
                for(int i=bL+1;i<bR;++i)
                if(tag[i])ans+=((LL)(dt[tag[i]]+pre[tag[i]][bR-1]-pre[tag[i]][bL])*B)+__,dt[tag[i]]+=B;
                for(int i=1;i<=top;++i)dt[sta[i]]=0;
                for(int i=bL+1;i<bR;++i)dt[tag[i]]=0;
            }
            _s[T]=(unsigned long long)ans;
            lst=ans;
        }
    }
    for(int i=m;i;--i)if(~_s[i])cout<<'\n'<<_s[i];
    return 0;
}