计蒜客-2017 ACM-ICPC 亚洲区(乌鲁木齐赛区)网络赛G题Query on a strin(树状数组+暴力更新)

题意:

给一个<=1e5的主串,一个<=10的匹配串,n次询问或操作,询问主串的[l, r]区间内与匹配串能匹配的个数(可重叠),操作给定一个位置pos和字符ch,将s[pos]改为ch。

思路:

由于匹配串长度很小,完全可以暴力去做,主串中与匹配串匹配的子串只有起点位置有值,然后通过树状数组维护区间和即可,不过查询时要注意一个小判断,区间有可能不足匹配串的长度。更新时,暴力去更新,改变一个字符,只会影响其前面少于十个位置,其后面少于十个位置。

代码:

#include <bits/stdc++.h>  
using namespace std;  
const int maxn = 1e5+5;  
char s[maxn], p[15], mk1, mk2;  
int a[maxn], tree[maxn];  
int t, n, len1, len2, x, y;  
int lowbit(int x){return x&(-x);}  
void update(int k, int val)  
{  
    while(k <= len1)  
    {  
        tree[k] += val;  
        k += lowbit(k);  
    }  
}  
int query(int k)  
{  
    int ans = 0;  
    while(k)  
    {  
        ans += tree[k];  
        k -= lowbit(k);  
    }  
    return ans;  
}  
void init()  
{  
    len1 = strlen(s+1);  
    len2 = strlen(p+1);  
    memset(tree, 0, sizeof tree);  
    for(int i = 1; i+len2-1 <= len1; ++i)  
    {  
        int t = 1;  
        while(t <= len2 && s[i+t-1] == p[t]) ++t;  
        a[i] = (t > len2);  
        update(i, a[i]);  
    }  
}  
int main()  
{  
    //freopen("in.txt", "r", stdin);  
    for(scanf("%d", &t); t--;)  
    {  
        scanf("%d", &n);  
        scanf("%s", s+1);  
        scanf("%s", p+1);  
        init();  
        while(n--)  
        {  
            scanf(" %c %d", &mk1, &x);  
            if(mk1 == 'C')  
            {  
                scanf(" %c", &mk2);  
                if(s[x] == mk2) continue;  
                s[x] = mk2;  
                int st = x-len2+1, ed = x+len2-1;  
                if(st < 1) st = 1;  
                if(ed > len1) ed = len1;  
                for(int i = st; i <= ed && i+len2-1 <= len1; ++i)  
                {  
                    int t = 1;  
                    while(t <= len2 && s[i+t-1] == p[t]) ++t;  
                    int chg = (t > len2);  
                    if(a[i]) a[i] = 0, update(i, -1);  
                    if(chg) a[i] = 1, update(i, 1);  
                }  
            }  
            else  
            {  
                scanf("%d", &y);  
                int ans = 0;  
                if(y-len2+1 >= x)   
                    printf("%d\n", query(y-len2+1)-query(x-1));  
                else puts("0");  
            }  
        }  
        puts("");
    }  
    return 0;  
}


继续加油~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值