牛客月赛36-科学幻想-(线段树+hash+二分)

本文介绍了一种使用线段树解决字符串操作和查询问题的方法,其中涉及字符串哈希、线段树的构建、更新和查询操作。在处理字符串是否勉强相同的问题时,通过二分查找确定不同位置并进行区间比较。代码中展示了具体的实现细节,并在最后给出了测试用例的处理过程。强调了积累经验和深入思考在解决此类问题中的重要性。
摘要由CSDN通过智能技术生成

J

题意:
给你一个字符串,然后有两种操作,一种是让a位置的字符变为b,一种是查询a到b和c到d的字符串是否勉强相同。勉强相同就是两个字符串最多有一个位置的字符不同。

思考:
很明显的线段树题意,所以这里维护一个线段树就行了,先对字符串进行hash,然后注意pushup和query的操作。值得注意的是,如何判断是否勉强相同呢,可以二分最远点,如果前半段是相同的那么l=mid,看看最远可以达到哪,那么l+1这个位置肯定是字符不一样,所以再判段一下l+2到r这段区间是否相同即可,唯一的注意点是如果刚开始就不同的话,要从l+1开始看。
这个没取模就是用了int为unsigned long long,自动取模。

代码:

int T,n,m,k;
char va[N];
int bas[N],p = 131;

struct node{
	int L,R;
	int sum;
}t[4*N];

void build(int node,int l,int r)
{
	t[node].L = l,t[node].R = r;
	if(l==r)
	{
		t[node].sum = va[l];
		return ;
	}
	int mid = (l+r)>>1;
	build(node_l,l,mid);build(node_r,mid+1,r);
	t[node].sum = t[node_l].sum*bas[r-mid]+t[node_r].sum;
}

void update(int node,int x,char value)
{
	if(t[node].L==x&&t[node].R==x)
	{
		t[node].sum = value;
		return ;
	}
	int mid = (t[node].L+t[node].R)>>1;
	if(x<=mid) update(node_l,x,value);
	if(x>mid) update(node_r,x,value);
	t[node].sum = bas[t[node].R-mid]*t[node_l].sum+t[node_r].sum;
}

int query(int node,int l,int r)
{
	if(t[node].L>=l&&t[node].R<=r) return t[node].sum;
	int mid = (t[node].L+t[node].R)>>1;
	if(r<=mid) return query(node_l,l,r);
	else if(l>mid) return query(node_r,l,r);
	else return query(node_l,l,mid)*bas[r-mid]+query(node_r,l,r); //左边区间再加上右边
}

signed main()
{
	IOS;
	cin>>n>>m>>va+1;
	bas[0] = 1;
	for(int i=1;i<=n;i++) bas[i] = bas[i-1]*p;
	build(1,1,n);
	while(m--)
	{
		int op,a,b,c,d;
		cin>>op;
		if(op==1)
		{
			int x;
			char ch;
			cin>>x>>ch;
			update(1,x,ch);
		}
		else
		{
			cin>>a>>b>>c>>d;
			if(b-a!=d-c)
			{
				cout<<"NO\n";
				continue;
			}
			int l = 0,r = b-a;
			while(l<r)
			{
				int mid = (l+r+1)>>1;
				if(query(1,a,a+mid)==query(1,c,c+mid)) l = mid;
				else r = mid-1;
			}
			if(query(1,a,a+l)!=query(1,c,c+l)) l = -1; //如果第一位都是不同的,下面要从l+1开始看
			if(a+l+2>b||query(1,a+l+2,b)==query(1,c+l+2,d)) cout<<"YES\n";
			else cout<<"NO\n";
		}
	}
	return 0;
}

总结:
多多积累经验,多多思考。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值