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",&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<<"\n";
            }else
            {
                cout<<ans+(getSum(pos2)-getSum(poss))<<"\n";
            }

        }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<<"\n";
}

int main()
{
    cin.sync_with_stdio(false);

    int t;
    scanf("%d",&t) ;
    while(t--)init();

    return 0;

} 
时间: 2024-08-29 21:13:47

KMP的正确使用法_x新疆网络赛Query on a string的相关文章

POJ3320 尺取法的正确使用法

一.前言及题意: 最近一直在找题训练,想要更加系统的补补思维,补补漏洞什么的,以避免被个类似于脑筋急转弯的题目干倒,于是在四处找书,找了红书.蓝书,似乎都有些不尽如人意.这两天看到了日本人的白书,重新读了一遍,其中若干章节写的非常务实也实践起来相当实用,于是这就是白书上面一道推荐的题目,用于训练尺取法的例题.考虑到最近老是读错题,所以就慢慢习惯于首先把个题目翻译成中文之后在进行解读: 杰西卡是个非常可爱的女孩子,因而有若干男孩子追她,最近他的考试要到了,她需要花相当多部分的时间在这件事情上面,吐

AJAX--XMLHttpRequest五步使用法

传统浏览方式和AJAX方式的不同 多数Web应用程序都使用请求/响应模型从服务器上获得完整的HTML页面.常常是点击一个按钮,等待服务器相应,在点击另一个按钮,然后在等待,这样一个反复的过程. 而AJAX是一种创建交互式网页的网页开发技术,其中XMLHttpRequest是核心的内容,它能够为页面中的javascript脚本提供特定的通信方式,从而使页面的javascript脚本和服务器之间形成动态交互的效果,XMLHTTPRequest的最大的优点是页面内的javascript脚本可以不用刷新

hdu6153 A Secret CCPC网络赛 51nod 1277 KMP

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=6153 题意: 给出两个字符串S1,S2,求S2的所有后缀在S1中出现的次数与其长度的乘积之和. 思路: CCPC网络赛题解: https://post.icpc-camp.org/d/714-ccpc-2017 http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1277   是一样的 将s1,s2翻转,转化为求前缀在s1中出

配置远程服务器,使hyper-v能够连接网络

一般远程服务器只有一个网卡和IP,如果你要在服务器上装虚拟机,那么要使虚拟机能够连接网络,必须要创建虚拟交换机. 如果创建虚拟交换机并桥接,那么就会改变IP地址,改变IP地址,就连接不上远程服务器.造成了一个死循环. 怎么解决呢,下面说一个方法,可以不桥接的方法,使hyper-v连接上网络 1.打开Hyper-v管理器--> 选择虚拟交换机管理器--创建一个内部虚拟交换机,请记住一定要是内部的 2.起名为xuni,然后点确定 3.打开网络和共享中心--点击左上角的  更改适配器设置,可以看到一共

CCPC 2017 网络赛

1001.我们的想法是,先构造n个要删掉的点,然后不断给图加边,使得每条边的其中一个点在n个点之中. 我们要使n个点之外的点尽量多,并且每次删掉的点在n个点之外. 贪心的决策是,每次操作,前n个点的度和令外的最大度的点度数相同. 然后删掉这个点之后,之后的操作,剩余的点也满足这个要求.所以度数最大的点必定与n个点有边. 于是可以这样构造,增加n批点(i = 1~n),每次增加n/i个点的,每个增加的点连出i条边到n个点. 这样,n个点每次增加的最大度数不超过1.但每次删点的时候(按n~1批的顺序

HDU 5008西安网络赛B题:后缀数组求第k小子串

思路:尼玛,这题搞了一天了,比赛的时候用了n^2的方法绝对T了,然后今天看别人代码看了一天才知道.后面感觉也挺容易的,就是没想到,之前做过SPOJ 694 705求过不同子串了,知道怎么求不同子串个数了,但是比赛的时候这个技巧竟然抛在脑后了,然后就不会了. 但是今天自己用了自己的两个后缀数组的模板(倍增和DC3)的都WA了,搞得自己真想跳楼去了!! 到现在都不知道到底是哪里错了,处理的方法和标准做法都一样,但是就是WA,然后用了别人的模板,再用自己的处理方法就过了,怀疑自己的两个模板是不是哪里错

HDOJ 5012 Dice--2014网络赛西安赛区F题

题目来源:http://acm.hdu.edu.cn/showproblem.php?pid=5012 Dice Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 307    Accepted Submission(s): 183 Problem Description There are 2 special dices on the

ACM总结——2017区域赛网络赛总结

从省赛回来至今4周,每周周末都在打网络赛,每次都是划水,总结下自己弱弱的ACM吧!划水水~~ 首先是新疆赛区,基本上都是图论相关的东西,全靠队友,自己翻水水,实力躺了5道. 然后是沈阳赛区,终于有点贡献了,单刷一道LIS,和队友找规律完成了number number number,最后完成4道,成功划水~~不得不说一下就是对于1009提交的事情,似乎是引起了很大的轰动,但是其实就个人感觉而言,随机提交靠运气过,也不至于这么被骂,又不是用脚本恶意提交,别人凭本事手动提交300+次也是别人的本事,弱

2018 CCPC网络赛

2018 CCPC网络赛 Buy and Resell 题目描述:有一种物品,在\(n\)个地点的价格为\(a_i\),现在一次经过这\(n\)个地点,在每个地点可以买一个这样的物品,也可以卖出一个物品,问最终赚的钱的最大值. solution 用两个堆来维护,一个堆维护已经找到卖家的,一个堆维护还没找到卖家的. 对于第\(i\)个地点,在已经找到卖家的堆里找出卖的钱的最小值,如果最小值小于\(a_i\),则将卖家换成\(i\),然后将原来的卖家放到没找到卖家的那里:如果最小值对于\(a_i\)