题意:
给你一个字符串,然后有两种操作,一种是让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;
}
总结:
多多积累经验,多多思考。