题解:【蓝桥杯 2022 国 AC】替换字符
大家好,我非常喜欢暴力数据结构,所以我用分块过了这道题。
[Ynoi2018]未来日记的弱弱弱弱弱化板,考虑经典的分块加并查集维护颜色。
记 \(id_{x,i}\) 表示第 \(x\) 个块中颜色 \(i\) 第一次出现的位置,\(col_i\) 表示第 \(i\) 个位置上的颜色,单次操作为 \(y \leftarrow x\)。
对于散块上的我们下放存的颜色暴力重构并查集。
对于整块上的我们分类讨论:
- 如果块里面有 \(x\) 没有 \(y\),直接跳过操作
- 如果块里面有 \(y\) 没有 \(x\),进行 \(id_{y,i} \leftarrow id_{x,i}\),\(col_i \leftarrow y\)
- 如果块里面有 \(x\) 有 \(y\),直接并查集把 \(x\) 并在 \(y\) 的儿子里
注意到一次操作整块内颜色数量最劣为不变,散块内最多增加一种新颜色,初始块内颜色数量不超过块长,因此时间复杂度为 \(\mathcal O((n+m)\sqrt{n})\),其中 \(m\) 是总颜色数量。
跑的比 \(26\) 棵线段树快多了,一时分不清谁是暴力。
#include<bits/stdc++.h>
#define int long long
using namespace std;
inline int read()
{
int s=0,w=1;
char c=getchar();
while(!isdigit(c)) {if(c=='-') w=-1; c=getchar();}
while(isdigit(c)) s=(s<<1)+(s<<3)+(c^48),c=getchar();
return s*w;
}
namespace LgxTpre
{
static const int MAX=100010;
static const int mod=998244353;
static const int INF=4557430888798830399;
int n,len;
int l,r,x,y;
char s[MAX],c1,c2;
int fa[MAX];
int find(int x)
{
if(fa[x]==x) return x;
return fa[x]=find(fa[x]);
}
int blo;
int L[MAX],R[MAX],pos[MAX];
int id[MAX][30],col[MAX],a[MAX];
inline void init()
{
scanf("%s",s+1); len=strlen(s+1);
for(int i=1;i<=len;++i)
a[i]=s[i]-'a'+1;
blo=sqrt(len);
for(int i=1;i<=blo;++i)
L[i]=(i-1)*blo+1,R[i]=i*blo;
if(R[blo]<len) ++blo,L[blo]=R[blo-1]+1,R[blo]=len;
for(int i=1;i<=blo;++i)
for(int j=L[i];j<=R[i];++j)
{
pos[j]=i;
if(!id[i][a[j]]) id[i][a[j]]=j,col[id[i][a[j]]]=a[j];
fa[j]=id[i][a[j]];
}
return;
}
inline void reset(int l,int r,int x,int y)
{
int now=pos[l];
for(int i=L[now];i<=R[now];++i) a[i]=col[find(i)],id[now][a[i]]=0;
for(int i=l;i<=r;++i) if(a[i]==x) a[i]=y;
for(int i=L[now];i<=R[now];++i)
{
if(!id[now][a[i]]) id[now][a[i]]=i,col[id[now][a[i]]]=a[i];
fa[i]=id[now][a[i]];
}
return;
}
inline void merge(int i,int x,int y)
{
if(!id[i][x]) return;
if(!id[i][y]) return id[i][y]=id[i][x],id[i][x]=0,col[id[i][y]]=y,void();
fa[id[i][x]]=id[i][y],id[i][x]=0;
return;
}
inline void solve(int l,int r,int x,int y)
{
if(x==y) return;
int lpos=pos[l],rpos=pos[r],con=0;
if(lpos==rpos)
{
for(int i=L[lpos];i<=R[lpos];++i)
if(col[find(i)]==x)
++con;
if(con) reset(l,r,x,y);
return;
}
con=0;
for(int i=l;i<=R[lpos];++i) if(col[find(i)]==x) ++con;
if(con) reset(l,R[lpos],x,y);
con=0;
for(int i=L[rpos];i<=r;++i) if(col[find(i)]==x) ++con;
if(con) reset(L[rpos],r,x,y);
for(int i=lpos+1;i<=rpos-1;++i) merge(i,x,y);
return;
}
inline void lmy_forever()
{
init();
n=read();
for(int i=1;i<=n;++i)
{
l=read(),r=read(),scanf("%c %c",&c1,&c2);
x=c1-'a'+1,y=c2-'a'+1;
solve(l,r,x,y);
}
for(int i=1;i<=len;++i)
putchar((char)(col[find(i)]+'a'-1));
return;
}
}
signed main()
{
LgxTpre::lmy_forever();
return (0-0);
}