题意:给出两个字符串,要进行两个操作,第一个操作是把某一个字符串的某一位字符改成另一个字符,另一个是查询从某一位置开始,最大的连续的stra[k]==strb[k]的个数。
思路:刚开始看10^6吓到了,但是查询只有10^5,时限10000ms,线段树是可以搞的。用数组记录字符串每一位的情况,如果这一位两个字符串相同,那么就为1,否则就为0,然后用线段树维护区间最大连续的前缀长度就行了。
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<vector>
#define inf 0x3f3f3f3f
#define Inf 0x3FFFFFFFFFFFFFFFLL
#define eps 1e-9
#define pi acos(-1.0)
using namespace std;
typedef long long ll;
const int maxn=1000000+10;
char stra[maxn],strb[maxn];
int sum[maxn<<2];
inline void PushUp(int m,int rt)
{
sum[rt]=sum[rt<<1];
if(sum[rt<<1]==m)
sum[rt]+=sum[rt<<1|1];
}
void build(int l,int r,int rt)
{
if(l==r)
{
sum[rt]=(stra[l-1]==strb[l-1])?1:0;
return ;
}
int m=(l+r)>>1;
build(l,m,rt<<1);
build(m+1,r,rt<<1|1);
PushUp(m-l+1,rt);
}
int Query(int L,int R,int l,int r,int rt,int &len)
{
if(l>=L&&r<=R)
{
len=r-l+1;
return sum[rt];
}
int m=(l+r)>>1;
if(m>=R)
return Query(L,R,l,m,rt<<1,len);
else if(m<L)
return Query(L,R,m+1,r,rt<<1|1,len);
int llen,rlen,res=0;
int s1=Query(L,R,l,m,rt<<1,llen);
int s2=Query(L,R,m+1,r,rt<<1|1,rlen);
if(s1==llen)
res=s1+s2;
else res=s1;
len=llen+rlen;
return res;
}
void Update(int p,int l,int r,int rt)
{
if(l==r)
{
sum[rt]=(stra[l-1]==strb[l-1])?1:0;
return ;
}
int m=(l+r)>>1;
if(m>=p)
Update(p,l,m,rt<<1);
else Update(p,m+1,r,rt<<1|1);
PushUp(m-l+1,rt);
}
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
int t,tcase=0;
scanf("%d",&t);
while(t--)
{
tcase++;
scanf("%s%s",stra,strb);
int n=min(strlen(stra),strlen(strb));
build(1,n,1);
int q,tp,wh,pos;
char cc[3];
printf("Case %d:\n",tcase);
scanf("%d",&q);
while(q--)
{
scanf("%d",&tp);
if(tp==1)
{
scanf("%d%d%s",&wh,&pos,cc);
if(pos>=n) continue;
if(wh==1)
stra[pos]=cc[0];
else strb[pos]=cc[0];
Update(pos+1,1,n,1);
}
else
{
scanf("%d",&pos);
if(pos>=n)
{
printf("0\n");
continue;
}
int tmp;
int ans=Query(pos+1,n,1,n,1,tmp);
printf("%d\n",ans);
}
}
}
return 0;
}