hdu3973 线段树+RK

本文介绍了一种结合字符串Hash技术和线段树的数据结构解决模式串匹配问题的方法。通过使用Hash值快速判断子串是否匹配给定的模式串集合,并利用线段树支持区间查询和单点更新操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:给出n个模式串和一个母串   然后修改操作是修改母串中的某一个字母  询问操作是给出一堆的区间 然后问这个区间是否满足n个模式串中的一个 

解法:修改的话就是线段树的单点修改  关键在于O(1)判断字符串 那么我们采用字符串hash就可以了 

把字符串看成一个素数进制的数 然后预处理每一位的位权 我们就可以把n个模式串全部保存在map里面 然后就可以判断是否存在了 

对于线段数,当然是储存每一个区间的hash值了 

当然这一题应该还有更好的做法 就是纯字符串的判断 这个先学习下

#include<map>
#include<cstdio>
#include<string.h>
#include<algorithm>
using namespace std;
#define ll long long
#define maxn 222222
#define ls (rt<<1)
#define rs (rt<<1|1)
#define mid ((l+r)>>1)
#define mul 27
map<ll,int>mp;
char ss[maxn*2];
ll ha[maxn<<2],p[maxn];
int scan()
{
    int res=0,ch;
    while(!((ch= getchar())>='0'&&ch<='9')){
        if(ch==EOF)return 1<<30;
    }
    res=ch-'0';
    while((ch=getchar())>='0'&&ch<='9')
        res=res*10+(ch-'0');
    return res;
}
void val(){
    int len=(int)strlen(ss); ll ans=0;
    for(int i=0;i<len;++i)ans+=(ss[i]-'a'+1)*p[len-i-1];
    mp[ans]=1;
}
int n,m,a,b;
char op[111];
void up(int rt,int l,int r){ha[rt]=ha[ls]*p[r-mid]+ha[rs];}
void build(int rt,int l,int r){
    if(l==r){ha[rt]=ss[l]-'a'+1;return ;}
    build(ls,l,mid);
    build(rs,mid+1,r);
    up(rt,l,r);
}
void ins(int rt,int l,int r,int pos,char x){
    if(l==r){ha[rt]=x-'a'+1;return ;}
    if(pos<=mid)ins(ls,l,mid,pos,x);
    if(mid<pos)ins(rs,mid+1,r,pos,x);
    up(rt,l,r);
}
ll query(int rt,int l,int r,int L,int R){
    if(L<=l&&r<=R)return ha[rt];
    if(R<=mid)return query(ls,l,mid,L,R);
    else if(mid<L)return query(rs,mid+1,r,L,R);
    else{
        ll ansl=query(ls,l,mid,L,mid),ansr=query(rs,mid+1,r,mid+1,R);
        return ansl*(p[R-mid])+ansr;
    }
}
int main(){
    int _;_=scan();
    ll ans=1;
    for(int i=0;i<200005;++i)p[i]=ans,ans*=mul;
    for(int z=1;z<=_;++z){
        mp.clear();
        scanf("%d",&n);
        while(n--)scanf("%s",ss),val();
        
        scanf("%s%d",ss+1,&m);n=(int)strlen(ss+1);
        
        build(1,1,n);printf("Case #%d:\n",z);
        while(m--){
            scanf("%s",op);
            if(*op=='Q'){
                a=scan(),b=scan();++a,++b;
                ll ans=query(1,1,n,a,b);
                if(mp[ans])printf("Yes\n");
                else printf("No\n");
            }else if(*op=='C'){
                a=scan();
                scanf("%s",op);++a;
                ins(1,1,n,a,op[0]);
            }
        }
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值