题解 P5692【[MtOI2019] 手牵手走向明天】
:修改笔误。
题意
给你一个长为 序列的 ,支持操作共 次:
- 将区间 中所有等于 的数修改为 ,即 ,执行 。
- 查询序列的区间 中 与 出现位置两两之差的最小值,即求 。
时间 1.5s,.
思路
前置知识:P5397 [Ynoi2018] 天降之物 - 第四分块。
第四分块的加强版。
一些记号需在我的第四分块题解中了解。
本篇题解中记号采用原题解中卡常部分之前的记号。
记 。
首先考虑比原题多了什么,多的是散块修改与散块询问。
先看较为简单的散块询问,显然,恢复两个散块的序列,扫的时候记录 即可,与整块基本无异。
然后就是非常恶心的散块修改。其中散块修改可能会使块中颜色数 ,但块中颜色数始终是 的,于是我们动态分配空间,具体地,记录未被使用的离散化值,在删除时加入,出现当前没有的数时分配一个离散化值给它。
对修改分类讨论。设散块为 ,修改区间为 。
- 区间 中无 ,直接跳过;
- 区间 中有 ,且 中无 :
- 区间 中无 :相当于整块修改,令 ;
- 区间 中有 :见下文。
- 区间 中有 ,且 中有 :
- 区间 中无 :见下文。
- 区间 中有 :见下文。
对于这三类情况,我们作以下处理:
- 若是 2.2 类,先取出一个未被使用的离散化值赋给 ;
- 若是 3.1 类,将 丢入未被使用的离散化值中并赋 ;
- 恢复整块序列 ,将 中的 修改为 ,对应的 修改为 ,并把这些被修改的位置取出,记作 。
- 若是 2.2 类,将所有 初始为极大值。
- 双指针记录 与最大的 满足 ,令 ,注意边界;
- 若是 2.2 或 3.2 类,按照与 4 和 5 同样的方式双指针更新 的答案;
- 更新 。
最棘手的散块修改就做完了,整块修改按照第四分块的方式即可,注意在重构时要将消失的 的离散化值丢进未被使用的离散化值中,并还原这块的 并修改。
由于每次只有 个散块修改,总共给 个块分别添加了 的势能,所以该算法复杂度正确,时空均为 。
这题的修改、询问仍是平凡的,仍可离线逐块处理,做到空间 ,时间常数也相应地减少了。但已经够难写了再写个这个就要吐了。
从第四分块改到这题,我的代码长度翻了一倍。
由于在第四分块的卡常,即使散块修改常数极大,我的代码运行速度仍不慢,跑到了最优解。最慢点甚至仍在 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~
分类:
题解
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话