计蒜客 Query on a string (线段树)

之前网络赛的一题,不会线段树。。现在填坑。

将第一个串处理一下,如果以当前字符为第一个字符,若出现了第二个字符串,用另一个数组将当前点记录为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");
    }
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值