题解:【蓝桥杯 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);
}
posted @ 2023-03-02 08:39  LgxTpre  阅读(92)  评论(1编辑  收藏  举报