AT_abc331_f [ABC331F] Palindrome Query 题解

分析

线段树。

每个节点维护两个值:s[lr]s[rl]。判断字串是否是回文直接就是询问的答案维护出来的两个值是否相同。

首先想到用线段树暴力维护。第一个值很显然是两个儿子的第一个值加起来,第二个值是反着加起来。得到很酷的代码:

il void up(int now){
	tr[now].ls=tr[now<<1].ls+tr[now<<1|1].ls,
	tr[now].rs=tr[now<<1|1].rs+tr[now<<1].rs;
	return ;
}
il void build(int now,int l,int r){
	tr[now].l=l,tr[now].r=r;
	if(l==r) tr[now].ls=tr[now].rs=s[l-1];
	else build(now<<1,l,(l+r)>>1),build(now<<1|1,((l+r)>>1)+1,r),up(now);
	return ; 
}
il void insert(int now,int k,int c){
	if(tr[now].l==tr[now].r){tr[now].ls=tr[now].rs=c;}
	else{
		int mid=tr[now].l+tr[now].r>>1;
		if(k<=mid) insert(now<<1,k,c);
		else insert(now<<1|1,k,c);
		up(now);
	}
	return ;
}
il tree query(int now,int l,int r){
	tree ans={0,0,"",""};
	if(tr[now].l>=l&&tr[now].r<=r) return tr[now];
	int mid=tr[now].l+tr[now].r>>1;
	if(l<=mid) ans=query(now<<1,l,r);
	if(mid<r){
		tree ans1=query(now<<1|1,l,r);
		ans.ls=ans.ls+ans1.ls,ans.rs=ans1.rs+ans.rs;
	}
	return ans;
}

然后就 TLE 了。原因是两个字符串相加复杂度太高。

考虑把字符串转化成数字。在字符串哈希中,第 i 个字符的值可以被表示为 si×blenimodk。这里 b 的值设一个大于 128 的就行了(我记得是)。

然后就没了。改变上传的价值。定义那时候的 len=rl+1,就可以把两个值算出来,即:fa.x=lson.x×brlen+rson.x,fa.y=rson.y×bmidl+1+lson.y

询问的时候在节点右端点包含询问区间右端点时注意一下左右限制即可。

代码

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define re register
#define il inline

const int N=1e6+10,p=1e9+7;
int n,q;
string s;
int b[N],bk=190;
struct tree{
	int l,r;
	int ls,rs;
}tr[N<<2];
il void up(int now){
	int mid=tr[now].l+tr[now].r>>1;
	tr[now].ls=(tr[now<<1].ls*b[tr[now].r-mid]%p+tr[now<<1|1].ls)%p,
	tr[now].rs=(tr[now<<1|1].rs*b[mid-tr[now].l+1]%p+tr[now<<1].rs)%p;
	return ;
}
il void build(int now,int l,int r){
	tr[now].l=l,tr[now].r=r;
	if(l==r) tr[now].ls=tr[now].rs=(s[l-1]+1-'a');
	else build(now<<1,l,(l+r)>>1),build(now<<1|1,((l+r)>>1)+1,r),up(now);
	return ; 
}
il void insert(int now,int k,int c){
	if(tr[now].l==tr[now].r){tr[now].ls=tr[now].rs=c;}
	else{
		int mid=tr[now].l+tr[now].r>>1;
		if(k<=mid) insert(now<<1,k,c);
		else insert(now<<1|1,k,c);
		up(now);
	}
	return ;
}
il tree query(int now,int l,int r){
	tree ans={0,0,0,0};
	if(tr[now].l>=l&&tr[now].r<=r) return tr[now];
	int mid=tr[now].l+tr[now].r>>1;
	if(l<=mid) ans=query(now<<1,l,r);
	if(mid<r){
		tree ans1=query(now<<1|1,l,r);
		if(l<=mid)
			ans.ls=(ans.ls*b[min(r,tr[now].r)-mid]%p+ans1.ls)%p,
			ans.rs=(ans1.rs*b[mid-max(tr[now].l,l)+1]%p+ans.rs)%p;
		else ans=ans1;
	}
	return ans;
}

il void solve(){
	cin>>n>>q>>s;
	b[0]=1;for(re int i=1;i<=n;++i) b[i]=b[i-1]*bk%p;
	build(1,1,n);
	for(re int i=1;i<=q;++i){
		int op;cin>>op;
		if(op==1){
			int k;char c;cin>>k>>c;
			insert(1,k,c+1-'a');
		}
		else{
			int l,r;cin>>l>>r;
			tree ans=query(1,l,r);
			if(ans.ls==ans.rs) cout<<"Yes\n";
			else cout<<"No\n";
		} 
	}
	return ;
}

signed main(){
	solve();
	return 0;
}
posted @   harmis_yz  阅读(14)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
点击右上角即可分享
微信分享提示