题解 P5692【[MtOI2019] 手牵手走向明天】

Upd2024.2.13:修改笔误。

Link

题意

给你一个长为 n 序列的 a,支持操作共 q 次:

  1. 将区间 [l,r] 中所有等于 x 的数修改为 y,即 i[l,r]ai=x,执行 aiy
  2. 查询序列的区间 [l,r]xy 出现位置两两之差的最小值,即求 minai=x,lirminaj=y,ljr|ij|

时间 1.5s,1n,q,ai105.

思路

前置知识:P5397 [Ynoi2018] 天降之物 - 第四分块

第四分块的加强版。

一些记号需在我的第四分块题解中了解。

本篇题解中记号采用原题解中卡常部分之前的记号。


bi=inpbeli,ai

首先考虑比原题多了什么,多的是散块修改与散块询问。

先看较为简单的散块询问,显然,恢复两个散块的序列,扫的时候记录 lasx,lasy 即可,与整块基本无异。

然后就是非常恶心的散块修改。其中散块修改可能会使块中颜色数 +1,但块中颜色数始终是 O(n) 的,于是我们动态分配空间,具体地,记录未被使用的离散化值,在删除时加入,出现当前没有的数时分配一个离散化值给它。

对修改分类讨论。设散块为 [L,R],修改区间为 [l,r]

  1. 区间 [l,r] 中无 x,直接跳过;
  2. 区间 [l,r] 中有 x,且 [L,R] 中无 y
    1. 区间 [L,l)(r,R] 中无 x:相当于整块修改,令 indi,inpi,x=y,inpi,y=inpi,x,inpi,x=0
    2. 区间 [L,l)(r,R] 中有 x:见下文。
  3. 区间 [l,r] 中有 x,且 [L,R] 中有 y
    1. 区间 [L,l)(r,R] 中无 x:见下文。
    2. 区间 [L,l)(r,R] 中有 x:见下文。

对于这三类情况,我们作以下处理:

  1. 若是 2.2 类,先取出一个未被使用的离散化值赋给 inpi,y
  2. 若是 3.1 类,将 inpi,x 丢入未被使用的离散化值中并赋 0
  3. 恢复整块序列 [L,R],将 [l,r] 中的 x 修改为 y,对应的 bk 修改为 inpi,y,并把这些被修改的位置取出,记作 st1,,top
  4. 若是 2.2 类,将所有 insi,k,inpi,y 初始为极大值。
  5. 双指针记录 i 与最大的 j 满足 stji,令 insi,bi,inpi,y=min(insi,bi,inpi,y,stj+1i,istj),注意边界;
  6. 若是 2.2 或 3.2 类,按照与 4 和 5 同样的方式双指针更新 x 的答案;
  7. 更新 firi,x,firi,y,seci,x,seci,y

最棘手的散块修改就做完了,整块修改按照第四分块的方式即可,注意在重构时要将消失的 x 的离散化值丢进未被使用的离散化值中,并还原这块的 ai,bi 并修改。

由于每次只有 O(1) 个散块修改,总共给 O(n) 个块分别添加了 O(1) 的势能,所以该算法复杂度正确,时空均为 O(nn)

这题的修改、询问仍是平凡的,仍可离线逐块处理,做到空间 O(n),时间常数也相应地减少了。但已经够难写了再写个这个就要吐了。


从第四分块改到这题,我的代码长度翻了一倍。

由于在第四分块的卡常,即使散块修改常数极大,我的代码运行速度仍不慢,跑到了最优解。最慢点甚至仍在 500ms 内。

以下代码仅供参考:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
namespace IO{//by cyffff

}
const int N=1e5+300,sq=255,nq=N/sq+10;
int n,q,blk,last,a[N],b[N],bl[nq],br[nq],bel[N],tp[nq],op[nq];
int fir[N],sec[N],ind[N];
short inp[N][nq],ins[N][sq+10],stk[nq][sq+10];
inline int site(int x,int y){
    if(x>y) swap(x,y);
    return x*sq+y;
}
inline void init(int l,int r){
    int d=bel[l],p=l-1;
    vector<int>vec;
    for(int i=l;i<=r;i++)
        vec.push_back(a[i]);
    sort(vec.begin(),vec.end());
    vec.resize(unique(vec.begin(),vec.end())-vec.begin());
    tp[d]=vec.size();
    for(int i=sq;i>tp[d];i--)
        stk[d][++op[d]]=i;
    for(int i=l;i<=r;i++)
        b[i]=lower_bound(vec.begin(),vec.end(),a[i])-vec.begin()+1,
        ind[p+b[i]]=a[i],inp[a[i]][d]=b[i];
    for(int i=l;i<=r;i++)
        sec[p+b[i]]=i;
    for(int i=r;i>=l;i--)
        fir[p+b[i]]=i;
    for(int i=1;i<=r-l+1;i++)
        for(int j=i+1;j<=r-l+1;j++)
            ins[p+i][j]=32767;
    for(int i=l;i<=r;i++)
        for(int j=i+1;j<=r;j++){
            int A=min(b[i],b[j]),B=max(b[i],b[j]);
            ins[p+A][B]=min(ins[p+A][B],(short)(j-i));
        }
}
inline void rebuild(int l,int r,int x,int y){
    int d=bel[l],p=l-1;
    int inpx=inp[x][d],inpy=inp[y][d];
    fir[p+inpy]=min(fir[p+inpy],fir[p+inpx]),sec[p+inpy]=max(sec[p+inpy],sec[p+inpx]);
    fir[p+inpx]=sec[p+inpx]=0,inp[x][d]=0;
    for(int i=l;i<=r;i++)
        a[i]=ind[p+b[i]];
    for(int i=l;i<=r;i++)
        if(a[i]==x) a[i]=y,b[i]=inpy;
    stk[d][++op[d]]=inpx;
    if(inpx>inpy){
        for(int i=1;i<=inpy;i++)
            ins[p+i][inpy]=min(ins[p+i][inpy],ins[p+i][inpx]),ins[p+i][inpx]=32767;
        for(int i=inpy+1;i<=inpx;i++)
            ins[p+inpy][i]=min(ins[p+inpy][i],ins[p+i][inpx]),ins[p+i][inpx]=32767;
        for(int i=inpx+1;i<=sq;i++)
            ins[p+inpy][i]=min(ins[p+inpy][i],ins[p+inpx][i]),ins[p+inpx][i]=32767;
    }else{
        for(int i=1;i<=inpx;i++)
            ins[p+i][inpy]=min(ins[p+i][inpy],ins[p+i][inpx]),ins[p+i][inpx]=32767;
        for(int i=inpx+1;i<=inpy;i++)
            ins[p+i][inpy]=min(ins[p+i][inpy],ins[p+inpx][i]),ins[p+inpx][i]=32767;
        for(int i=inpy;i<=sq;i++)
            ins[p+inpy][i]=min(ins[p+inpy][i],ins[p+inpx][i]),ins[p+inpx][i]=32767;
    }
}
int st[sq+10],top;
inline void solve1(int L,int R,int l,int r,int x,int y,int fl){
    int d=bel[L],p=L-1;
    int inpx=inp[x][d],inpy;
    if(!fl){
        inpy=stk[d][op[d]--],inp[y][d]=inpy,ind[p+inpy]=y;
    }
    else inpy=inp[y][d];
    if(fl==2){
        inp[x][d]=0,ind[p+inpx]=0;
        fir[p+inpx]=sec[p+inpx]=0;
        stk[d][++op[d]]=inpx;
    }
    top=0;
    for(int i=l;i<=r;i++)
        if(a[i]==x) a[i]=y,b[i]=inpy,st[++top]=i;
    st[++top]=1e9;
    if(!fl){
        for(int i=L;i<=R;i++){
            int A=b[i],B=inpy;
            if(A>B) swap(A,B);
            ins[p+A][B]=32767;
        }
    }
    for(int i=L,j=1;i<=R;i++){
        while(st[j]<=i) j++;
        j--;
        int A=b[i],B=inpy;
        if(A>B) swap(A,B);
        if(j!=top-1){
            if(j==0) ins[p+A][B]=min(ins[p+A][B],(short)(st[j+1]-i));
            else ins[p+A][B]=min({ins[p+A][B],(short)(i-st[j]),(short)(st[j+1]-i)});
        }else{
            ins[p+A][B]=min(ins[p+A][B],(short)(i-st[j]));
        }
    }
    if(fl!=2){
        top=0;
        for(int i=L;i<=R;i++)
            if(a[i]==x) st[++top]=i;
        st[++top]=1e9;
        for(int i=L;i<=R;i++){
            int A=b[i],B=inpx;
            if(A>B) swap(A,B);
            ins[p+A][B]=32767;
        }
        for(int i=L,j=1;i<=R;i++){
            while(st[j]<=i) j++;
            j--;
            int A=b[i],B=inpx;
            if(A>B) swap(A,B);
            if(j!=top-1){
                if(j==0) ins[p+A][B]=min(ins[p+A][B],(short)(st[j+1]-i));
                else ins[p+A][B]=min({ins[p+A][B],(short)(i-st[j]),(short)(st[j+1]-i)});
            }else{
                ins[p+A][B]=min(ins[p+A][B],(short)(i-st[j]));
            }
        }
    }
    for(int i=L;i<=R;i++)
        if(a[i]==x) sec[p+inpx]=i;
    for(int i=R;i>=L;i--)
        if(a[i]==x) fir[p+inpx]=i;
    for(int i=L;i<=R;i++)
        if(a[i]==y) sec[p+inpy]=i;
    for(int i=R;i>=L;i--)
        if(a[i]==y) fir[p+inpy]=i;
}
inline void solve2(int l,int r,int x,int y){
    int bL=bel[l];
    int p=bl[bL]-1,L=bl[bL],R=br[bL],inpx=inp[x][bL],inpy=inp[y][bL];
    if(!inpx) return ;
    for(int i=L;i<=R;i++)
        a[i]=ind[p+b[i]];
    bool fl=0;
    for(int i=l;i<=r;i++)
        if(a[i]==x) fl=1;
    if(!fl) return ;
    fl=0;
    for(int i=L;i<l;i++)
        if(a[i]==x) fl=1;
    for(int i=r+1;i<=R;i++)
        if(a[i]==x) fl=1;
    if(!inpy){
        if(fl) solve1(L,R,l,r,x,y,0);
        else ind[p+inpx]=y,inp[x][bL]=0,inp[y][bL]=inpx;
    }else{
        if(fl) solve1(L,R,l,r,x,y,1);
        else solve1(L,R,l,r,x,y,2);
    }
}
int main(){
    n=read(),q=read();
    for(int i=1;i<=n;i++)
        a[i]=read();
    for(int i=1;i<=n;i+=sq){
        blk++;
        bl[blk]=i,br[blk]=min(i+sq-1,n);
        for(int j=bl[blk];j<=br[blk];j++)
            bel[j]=blk;
        init(bl[blk],br[blk]);
    }
    while(q--){
        int opt=read(),l=read(),r=read(),x=read(),y=read();
        if(opt==2){
            int ans=n+1,bL=bel[l],bR=bel[r],lasx=-1e9,lasy=-1e9;
            if(x==y){
                if(bL==bR){
                    int p=bl[bL]-1;
                    for(int i=l;i<=r;i++)
                    if((a[i]=ind[p+b[i]])==x) ans=0;
                }else{
                    int p=bl[bL]-1;
                    for(int i=l;i<=br[bL];i++)
                    if((a[i]=ind[p+b[i]])==x) ans=0;
                    p=bl[bR]-1;
                    for(int i=bl[bR];i<=r;i++)
                    if((a[i]=ind[p+b[i]])==x) ans=0;
                }
                for(int i=bL+1;i<=bR-1;i++)
                    if(inp[x][i]) ans=0;
                if(ans==n+1) puts("-1");
                else printf("%d\n",ans);
                continue;
            }
            if(bL==bR){
                int p=bl[bL]-1;
                for(int i=l;i<=r;i++)
                    a[i]=ind[p+b[i]];
                for(int i=l;i<=r;i++){
                    if(a[i]==x) ans=min(ans,i-lasy),lasx=i;
                    if(a[i]==y) ans=min(ans,i-lasx),lasy=i;
                }
            }else{
                int p=bl[bL]-1;
                for(int i=l;i<=br[bL];i++)
                    a[i]=ind[p+b[i]];
                for(int i=l;i<=br[bL];i++){
                    if(a[i]==x) ans=min(ans,i-lasy),lasx=i;
                    if(a[i]==y) ans=min(ans,i-lasx),lasy=i;
                }
                for(int i=bL+1;i<=bR-1;i++){
                    int inpx=0,inpy=0,p=bl[i]-1;
                    if(inpx=inp[x][i]) ans=min(ans,fir[p+inpx]-lasy);
                    if(inpy=inp[y][i]) ans=min(ans,fir[p+inpy]-lasx);
                    if(inpx&&inpy){
                        int q=ins[p+min(inpx,inpy)][max(inpx,inpy)];
                        if(q!=32767) ans=min(ans,q);
                    }
                    if(inpx) lasx=sec[p+inpx];
                    if(inpy) lasy=sec[p+inpy];
                }
                p=bl[bR]-1;
                for(int i=bl[bR];i<=r;i++)
                    a[i]=ind[p+b[i]];
                for(int i=bl[bR];i<=r;i++){
                    if(a[i]==x) ans=min(ans,i-lasy),lasx=i;
                    if(a[i]==y) ans=min(ans,i-lasx),lasy=i;
                }
            }
            if(ans==n+1) puts("-1");
            else printf("%d\n",ans);
        }else{
            if(x==y) continue;
            int bL=bel[l],bR=bel[r];
            if(bL==bR){
                solve2(l,r,x,y);
            }else{
                solve2(l,br[bL],x,y);
                solve2(bl[bR],r,x,y);
                for(int i=bL+1;i<=bR-1;i++){
                    int t=inp[x][i],p=bl[i]-1;
                    if(!t) continue;
                    if(!inp[y][i])
                        ind[p+t]=y,inp[x][i]=0,inp[y][i]=t;
                    else
                        rebuild(bl[i],br[i],x,y);
                }
            }
        }
    }
    flush();
}

再见 qwq~

posted @   ffffyc  阅读(2)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话
点击右上角即可分享
微信分享提示