之前网络赛的一题,不会线段树。。现在填坑。
将第一个串处理一下,如果以当前字符为第一个字符,若出现了第二个字符串,用另一个数组将当前点记录为1,否则为0;如样例AABBABA AA,记录的数组为1000000,然后以这个记录数组建线段树,查询就是求这个区间的和,查询范围是(l,r-strlen(p)+1),更改就是线段树单点更新。
#include <cstdio>
#include <cstring>
#include <algorithm>
#define lid id<<1
#define rid id<<1|1
using namespace std;
const int maxn=100010;
char t[maxn],p[15];
int s1[maxn]; //01;
int ans,tLen,pLen;
int smatch(int st)
{
int bo=1;
for(int i=st,j=0;j<pLen;i++,j++)
{
if(t[i]!=p[j])
{
bo=0;break;
}
}
return bo;
}
struct node
{
int l,r,sum;
}tr[maxn*4];
void push_up(int id)
{
tr[id].sum=tr[lid].sum+tr[rid].sum;
}
void build(int id,int l,int r)
{
tr[id].l=l,tr[id].r=r;
if(l==r)
{
s1[l]=tr[id].sum=smatch(l);
return;
}
int mid=(l+r)>>1;
build(lid,l,mid);
build(rid,mid+1,r);
push_up(id);
}
void updata(int id,int x,int v)
{
if(tr[id].l==tr[id].r) tr[id].sum=v;
else{
int mid=(tr[id].l+tr[id].r)>>1;
if(x<=mid) updata(lid,x,v);
else if(x>mid) updata(rid,x,v);
push_up(id);
}
}
int query(int id,int l,int r)
{
if(tr[id].l==l && tr[id].r==r) return tr[id].sum;
else{
int mid=(tr[id].l+tr[id].r)>>1;
if(r<=mid) return query(lid,l,r);
else if (l>mid) return query(rid,l,r);
else return (query(lid,l,mid)+query(rid,mid+1,r));
}
}
int main()
{
int T,m;
scanf("%d",&T);
while(T--)
{
scanf("%d",&m);
scanf("%s%s",t,p);
tLen=strlen(t),pLen=strlen(p);
build(1,0,tLen-1);
while(m--)
{
char ch;
scanf(" %c",&ch);
if(ch=='Q')
{
int x,y;
scanf("%d%d",&x,&y);
x--,y--; //注意线段树区间是[0,tlen-1]
y=y-pLen+1;
if(x<=y) printf("%d\n",query(1,x,y));
else printf("0\n");
}
else if(ch=='C')
{
int x;char val;
scanf("%d %c",&x,&val);
t[x-1]=val;
int Begin =max((x-pLen),0);
for(int i=Begin;i<=x-1;i++)
{
int flag=smatch(i);
if(flag!=s1[i]) updata(1,i,flag),s1[i]=flag;
}
}
}
printf("\n");
}
}