zoukankan      html  css  js  c++  java
  • KMP的正确使用法_x新疆网络赛Query on a string

    Query on a string

    题意,给定一个大字符串,给定一个小模式串,定义 两种不同的任务模式,分别是查询和更改:

    查询对应区间内,有多少个匹配到位的数字;

    修改某一位的某一个字母。

    于是直觉告诉我们是KMP,而且需要一个单点更新,动态查询的数据结构——直觉上认为树状数组比较合适执行这个任务。

    于是,开个大大数组,保存每次匹配时对应位的四字母的匹配指针的位置。

    每次扫描到了模式串长度都往树状数组里面存入相关元素。

    每次修改之后应当从新就地走一遍模式串,更新相关内容,注意,每次匹配到的新的结果和老结果向同的时候就应当退出。

    #include<bits/stdc++.h>
    using namespace std;
    
    const long long MAXN=200233;
    char str[MAXN];
    char str2[23];
    int lenOfSub;
    int flags[MAXN];
    int f[MAXN];
    
    
    int n,m;
    
    int tree[MAXN];
    void insert(int pos,int key)
    {
        pos+=23;
        while(pos<MAXN)
        {
            tree[pos]+=key;
            pos+=pos&(-pos);
        }
    }
    int getSum(int pos)
    {
        pos+=23;
        int ret=0;
        while(pos)
        {
            ret+=tree[pos];
            pos-=pos&(-pos);
        }return ret;
    }
    
    
    void get_fail()
    {
        int len=strlen(str2);
        lenOfSub=len;
        f[0]=f[1]=0;
        for(int i=1;i<len;++i)
        {
            int j=f[i];
            while(j&&str2[i]!=str2[j])j=f[j];
            f[i+1]= str2[i]==str2[j]? j+1:0;
        }
    }
    void get_match()
    {
        int j=f[0];
        int len=strlen(str);
        for(int i=0;i<len;++i)
        {
            while(j&&str[i]!=str2[j])j=f[j];
            j= str[i]==str2[j]? j+1:0;
            flags[i]=j;
        }
    //    for(int i=0;i<len;++i)cout<<flags[i]<<ends;
    //    cout<<endl;
    }
    
    
    void init()
    {
        scanf("%d
    ",&n);
        memset(tree,0,sizeof(tree));
        memset(f,0,sizeof(f));
        gets(str);
        gets(str2);
        get_fail();
        get_match();
        int len=strlen(str);
        for(int i=1;i<len;++i)
        {
            if(flags[i]==lenOfSub)insert(i,1);
        }
        for(int it=0;it<n;++it)
        {
            char cm[2];
            scanf("%s",cm);
            
            if(cm[0]=='Q')
            {
                int pos1;int pos2;
                scanf("%d%d",&pos1,&pos2);pos1--;pos2--;
                int poss=-1;int j=f[0];
                    int ans=0;
                for(int i=pos1;i<=pos2;++i)
                {
                    while(j&&str[i]!=str2[j])j=f[j];
                    j= str[i]==str2[j]? j+1:0;
                    if(j==lenOfSub)ans++;
                    if(j==flags[i])
                    {
                        poss=i;
                        break;
                    }
                }
                if(poss==-1)
                {
                    cout<<ans<<"
    ";
                }else
                {
                    cout<<ans+(getSum(pos2)-getSum(poss))<<"
    ";
                }
                
            }else
            {
                int pp;
                scanf("%d%s",&pp,cm);
                pp--;
                str[pp]=cm[0];
                int j=0;
                if(pp)j=flags[pp-1];
                for(int i=pp;i<len;++i)
                {
                    while(j&&str[i]!=str2[j])j=f[j];
                    j= str[i]==str2[j]? j+1:0;
                    if(flags[i]==j)break;
                    if(flags[i]==lenOfSub)insert(i,-1);
                    if(j==lenOfSub)insert(i,1);
                    flags[i]=j;
                }
            }    
        } 
        
        cout<<"
    ";
    }
    
    int main()
    {
        cin.sync_with_stdio(false);
        
        int t;
        scanf("%d",&t) ;
        while(t--)init();
        
        
        return 0;
        
    } 
  • 相关阅读:
    AcWing每日一题--最大的和
    使用 *args 和 **kwargs 的含义
    Python的八大基本数据类型之 元组、列表、字典
    条件判断与if嵌套
    数据拼接与转换
    print()函数与转义字符
    BEGIN-2 序列求和
    BEGIN-1 A+B问题
    并发编程——进程——生产者消费者模型
    并发编程——进程——进程的同步与数据共享
  • 原文地址:https://www.cnblogs.com/rikka/p/7594628.html
Copyright © 2011-2022 走看看