2017 ACM-ICPC 亚洲区(乌鲁木齐赛区)网络赛 Query on a string(字符串+树状数组)

41 篇文章 0 订阅
37 篇文章 0 订阅

啊啊啊,字符串几乎完全不懂啊.
迷迷糊糊的看了下kmp,感觉也和纯套模版没区别了..
这题一看到就觉得是线段树什么的,但是并没有想到只是通过数据结构来方便求和(好菜啊好菜啊好菜啊).
幻想一些直接query,把字符串分开再组合就能得到答案的方法..
用kmp先整体处理,在每一个小修改时,复杂度是很低的.
复杂度约等于nlogn

/*  xzppp  */
#include <iostream>
#include <vector>
#include <cstdio>
#include <string.h>
#include <algorithm>
#include <queue>
#include <map>
#include <set>
#include <stack>
#include <list>
#include <string>
#include <cmath>
#include <bitset>
#include <iomanip>
using namespace std;
#define FFF freopen("in.txt","r",stdin);freopen("out.txt","w",stdout);
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define MP make_pair
#define PB push_back
#define _ %MOD
typedef long long  LL;
typedef unsigned long long ULL;
typedef pair<int,int > pii;
typedef pair<LL,LL> pll;
typedef pair<double,double > pdd;
typedef pair<double,int > pdi;
const int MAXN = 1e5+17;
const int MAXM = 1e6+17;
const int MAXV = 2*1e3+17;
const int BIT = 15+3;
const int INF = 0x7f7f7fff;
const LL INFF = 0x3f3f3f3f3f3f3f3f;
const int MOD = 1e9+7;
int Next[MAXN],uset[MAXN];
string targ,pat;
int bit[MAXN];
void add(int p,int x)
{
    int n = targ.size();
    while(p<=n)
    {
        bit[p]+=x;
        p += p&-p;
    }
}
int sum(int p)
{
    int n = targ.size();
    int res = 0;
    while(p>0)
    {
        res += bit[p];
        p -= p&-p;
    }
    return res;
}
void init(string pat)
{
    int lp = pat.length();
    for (int i=1;i<lp;i++)
    {
        int j=Next[i];
        while(j && pat[i]!=pat[j])
            j=Next[j];
        Next[i+1]=(pat[i]==pat[j])?j+1:0;
    }
}
void kmp(string targ,string pat)
{
    init(pat);
    int lt = targ.length(),lp = pat.length();
    for (int i=0,j = 0;i<lt;i++)
    {
        while (j&&targ[i]!=pat[j]) j=Next[j];
        if (targ[i]==pat[j]) j++;
        if (j==lp)
            {
                add(i+1,1);
                uset[i+1] = 1;
                //cout<<i+1<<endl;
                j = Next[j];
            }
    }
}
int main()
{
    #ifndef ONLINE_JUDGE 
    FFF
    #endif
    int t;
    cin>>t;
    while(t--)
    {
        memset(bit, 0, sizeof(bit));
        memset(uset, 0, sizeof(uset));
        memset(Next, 0, sizeof(Next));
        int n;
        cin>>n;
        cin>>targ>>pat;
        kmp(targ,pat);
        for (int i = 0; i < n; ++i)
        {
            char cmd[5];
            scanf("%s",cmd);
            if(cmd[0]=='Q')
            {
                //cout<<targ<<endl;
                int s,t;
                scanf("%d%d",&s,&t);
                //cout<<t<<"  "<<s+pat.size()-2<<endl;
                printf("%d\n", sum(t)-sum(s+pat.size()-2));
            }
            else
            {
                int p;
                char cg[5];
                scanf("%d%s",&p,cg);
                targ[p-1] = cg[0];
                //cout<<targ<<endl; 
                int s = max(1,p-(int)pat.size()+1);
                for (int i = s; i <= p ; ++i)
                {
                    bool can = true;
                    for (int j = 1; j <= pat.size(); ++j)
                    {
                        if(targ[i+j-2]!=pat[j-1])
                        {
                            can = false;
                            break;
                        }
                    }
                    int cgp = i+pat.size()-1;
                    if(!can&&uset[cgp]==1)
                    {
                        add(cgp,-1);
                        uset[cgp] = 0;
                    }
                    if(can&&uset[cgp]!=1)
                    {
                        uset[cgp] = 1;
                        add(cgp,1);
                    }
                }
            }
        }
        printf("\n");
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值