计蒜客-树状数组&KMP-Query on a string

https://nanti.jisuanke.com/t/16956
写了好多次,用我自己的kmp写法一直 tle。
用kmp处理母串中每个位置 失配模式串的位置
然后用树状数组处理,(据说线段树会卡??)
kmp还要好好学。。

#include<bits/stdc++.h>
using namespace std;
/*
每次维护保存一个  当前位置失配的位置。
(相当于维护一个next,因为next是模式串的 最长的 前缀和后缀一起出现的地方,所以我们也可以理解为他是失配的地方)
*/
const int maxn=1e5+2000;
int sum[maxn];
int cc[maxn];
char  s[maxn];
char t[maxn];
int len1;
int len2;
int lowbit(int x){
     return x&(-x);
}
void add(int u,int s){
     while(u<maxn){
         sum[u]+=s;
         u+=lowbit(u);
     }
}
int sums(int u){
      int all=0;
     while(u){
        all+=sum[u];
        u-=lowbit(u);
     }
    return all;
}
int nex[maxn];
/*void next(){
      //int len=s2.length();
      int i=0;//下面就要计算 next数组了
      int k=-1;//记录最大next
      nex[0]=0;
      while(i<len2){
          if(k==-1||t[i]==t[k]){
             i++;k++;
             nex[i]=k;//记住,nex i是i-1串的 最长前后缀。
          }
          else
            k=nex[k];//递归,在最长 前后缀中间继续寻找。
      }
}
void update(int len3){

     int k;
     if(len3>0)
     k=cc[len3-1];
     else
       k=0;
     //cout<<"ini"<<k<<endl;
     //cout<<len1<<"???"<<len3<<endl;
     for(int i=len3;i<len1&&i<len3+len2;i++){
         if(cc[i]==len2)add(i+1,-1);
         while(k>0&&s[i]!=t[k])
               k=nex[k];
         if(s[i]==t[k])
             k++;
         if(k==len2)
            add(i+1,1);
            cc[i]=k;
     }
     //puts("ccccc");
     //for(int i=0;i<len1;i++)
       // cout<<cc[i]<<" ";
     //cout<<endl;
}
int getsum(){
    //int len1=strlen(s);
    //int len2=strlen(t);
    int k=0;
    for(int i=0;i<len1;i++){
         while(k>0&&s[i]!=t[k])
             k=nex[k];
         if(s[i]==t[k])
             k++;
         if(k==len2)
            add(i+1,1);
            cc[i]=k;
    }
}*/
void KMP()
{
    int len=strlen(t);
    nex[0]=0;
    for(int i=1,k=0;i<len;i++)
    {
        while(k>0 && t[i]!=t[k]) k=nex[k-1];
        if(t[i]==t[k]) k++;
        nex[i]=k;
    }
}
void  getCal(){
    len1 = strlen(s);
    len2 = strlen(t);
    for(int i=0,k=0;i<len1;i++) {
        while(k>0&& s[i]!=t[k]) k=nex[k-1];
        if(s[i]==t[k]) k++;
        cc[i] = k;
        if(k==len2) add(i+1,1);
    }
}
void update(int pos){
    int k=0;
    if(pos>0) k=cc[pos-1];
    for(int i=pos;i<pos+len2 && i<len1;i++)
    {
        if(cc[i]==len2) add(i+1,-1);
        while(k>0 && s[i]!=t[k]) k=nex[k-1];
        if(s[i]==t[k]) k++;
        if(k==len2) add(i+1,1);
        cc[i]=k;
    }
}
void init(){
   memset(cc,0,sizeof(cc));
   memset(sum,0,sizeof(sum));
}
int main()
{   //ios::sync_with_stdio(false);
    int T,m,a,b;
   char ch,ch2;
    scanf("%d",&T);
    while(T--){
        init();  
        scanf("%d",&m);
          getchar();
          scanf("%s",s);
          scanf("%s",t);
          KMP();
          len1=strlen(s);
          len2=strlen(t);
           getCal();
          for(int i=0;i<m;i++){
              scanf(" %c",&ch);
              if(ch=='Q'){
                 scanf("%d%d",&a,&b);
                 //cout<<a<<" "<<b<<endl;
                 if(b-a+1<len2){
                    puts("0");
                    continue;
                    }
                 else
                 printf("%d\n",sums(b)-sums(a+len2-2));
              }
              else{
                  getchar();
                  scanf("%d",&a);
                  getchar();
                  scanf("%c",&ch2);
                  s[a-1]=ch2;
                  update(a-1);
              }

          }
        puts("");
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值