Kefa and Watch线段树+字符串哈希

http://codeforces.com/problemset/problem/580/E

https://blog.csdn.net/snowy_smile/article/details/48677011 


#include<bits/stdc++.h>
#define ls o<<1
#define rs o<<1|1
typedef long long LL; 
template<class T> inline void gmax(T &a,T b){if(b>a)a=b;}
template<class T> inline void gmin(T &a,T b){if(b<a)a=b;}
using namespace std;

const int W=13,Z=1e9+7,N=1e5+10;
void fre(){
	freopen("in.txt","r",stdin);
}
LL b[N],s[N];
struct A{
	int l,r;
	int v,w;
}a[1<<18];

void pushup(int o){
	a[o].v=(a[ls].v+a[rs].v)%Z;
}
void pushdown(int o){
	if(~a[o].w){
		a[ls].w=a[rs].w=a[o].w;
		a[ls].v=(s[a[ls].r]-s[a[ls].l-1]+Z)*a[o].w%Z;
		a[rs].v=(s[a[rs].r]-s[a[rs].l-1]+Z)*a[o].w%Z;
		a[o].w=-1;
	}
}
void build(int o, int l, int r){
	a[o].l=l;
	a[o].r=r;
	a[o].w=-1;
	if(l==r){
		char ch;scanf("%c",&ch);
		int x=ch-48;
		a[o].v=x*b[l]%Z;
		return;
	}
	int m=(l+r)>>1;
	build(ls,l,m);
	build(rs,m+1,r);
	pushup(o);
}
void change(int o, int l, int r, int w){
	if (a[o].l==l&& a[o].r==r){
		a[o].w=w;
		a[o].v=(s[r]-s[l-1]+Z)*w%Z;
		return ;
	}
	pushdown(o);
	int  m=(a[o].r+a[o].l)>>1;
	if(r<=m)change(ls,l,r,w);
	else if(l>m)change(rs,l,r,w);
	else{
		change(ls,l,m,w);
		change(rs,m+1,r,w);
	}
	pushup(o);
}
int check(int o,int l, int r){
	if(a[o].l==l&&a[o].r==r){
		return a[o].v;
	}
	pushdown(o);
	int m=(a[o].l+a[o].r)>>1;
	if(r<=m)return check(ls,l,r);
	else if(l>m) return check(rs,l,r);
	else return (check(ls,l,m)+check(rs,m+1,r))%Z;
}
int n,m,g;
int main(){
//	fre();
	b[0]=0;b[1]=1;for(int i=2;i<N;i++)b[i]=b[i-1]*W%Z;
	s[0]=0;s[1]=1;for(int i=2;i<N;i++)s[i]=(s[i-1]+b[i])%Z;
	while(~scanf("%d%d%d",&n,&m,&g)){
		getchar();
		build(1,1,n);
		m+=g;
		while(m--){
			int o,l,r,w;
			scanf("%d%d%d%d",&o,&l,&r,&w);
			if(o==1)change(1,l,r,w);
			else{
				if(r-l<w)printf("YES\n");
				else{
					int v1=check(1,l,r-w);v1=v1*b[w+1]%Z;
					int v2=check(1,l+w,r);
					if(v1==v2)printf("YES\n");
					else printf("NO\n");
				}
			}
		}
	}
	return 0;
}



 这个题注意几点

1. 做哈希时,首先处理出每一位的哈希值

2.由于区间值会相同,因此哈希前缀有意义

3.线段树如果匹配上区间就返回,否则递归更新根区间

4.最后哈希值比较要乘哈希偏移值

#include<bits/stdc++.h>
#define ls o<<1
#define rs o<<1|1
typedef long long LL; 
template<class T> inline void gmax(T &a,T b){if(b>a)a=b;}
template<class T> inline void gmin(T &a,T b){if(b<a)a=b;}
using namespace std;

const int W=13,Z=1e9+7,N=1e5+10;
void fre(){
	freopen("in.txt","r",stdin);
}

char s[N];
int main(){
//	fre();
	int n,m,g;
	while(~scanf("%d%d%d%s",&n,&m,&g,s+1)){
		m+=g;
		while(m--){
			int o,l,r,c;
			scanf("%d%d%d%d",&o,&l,&r,&c);
			if(o==1){
				memset(s+l,c+'0',r-l+1);
			}
			else{
				puts(memcmp(s+l,s+l+c,r-l-c+1)?"NO":"YES");
			}
		}
	}
	return 0;
}

 

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值