• hdu3973 AC's String 线段树+字符串hash


    题目链接:http://icpc.njust.edu.cn/Problem/Hdu/3973/

    题意是:给出一个模式串,再给出一些串组成一个集合,操作分为两种,一种是替换模式串中的一个字符,还有一种是查询模式串中[l,r]区间的字符串有没有出现在字符串集合中。

    由于数据量很大,只能用O(nlogn)复杂度的算法才能通过,我们首先想到区间查询的操作线段树是可以做的,但是怎么样将一个子串唯一化呢?这就要说道字符串哈希了,我的做法是通过字符串哈希将字符串变成31进制数并且让它自然溢出,也就是对2^64取模。然后我们想到如何合并左右子区间呢?根据哈希的思想我们很容易想到:如果右区间的hash值为hash1,左区间的hash值为hash2,右区间的长度是len,则合并之后的hash=hash2*31^len+hash1,根据这样的策略可以知道任何区间的子串的hash值。

    代码如下:

      1 #include<bits/stdc++.h>
      2 using namespace std;
      3 typedef unsigned int ui;
      4 typedef long long ll;
      5 typedef unsigned long long ull;
      6 #define pf printf
      7 #define mem(a,b) memset(a,b,sizeof(a))
      8 #define prime1 1e9+7
      9 #define prime2 1e9+9
     10 #define pi 3.14159265
     11 #define lson l,mid,rt<<1
     12 #define rson mid+1,r,rt<<1|1
     13 #define scand(x) scanf("%llf",&x) 
     14 #define f(i,a,b) for(int i=a;i<=b;i++)
     15 #define scan(a) scanf("%d",&a)
     16 #define dbg(args) cout<<#args<<":"<<args<<endl;
     17 #define pb(i) push_back(i)
     18 #define ppb(x) pop_back(x)
     19 #define inf 0x3f3f3f3f
     20 #define maxn 100010
     21 #define maxm 2000005
     22 int n,m,x,y;
     23 ll pp=31;
     24 ll t[maxn<<2],p[maxm];
     25 char s[maxm],a[maxm];
     26 void init()
     27 {
     28     p[0]=1;
     29     f(i,1,maxm-1)
     30     {
     31         p[i]=p[i-1]*pp;
     32     }
     33 }
     34 ll gethash(char* s)//获取字符串的哈希值 
     35 {
     36     ll ans=0;
     37     f(i,0,strlen(s)-1)
     38     {
     39         ans=ans*pp+s[i]-'a'+1;//哈希值自然溢出,也就是对2^64取模 
     40     }
     41     return ans;
     42 }
     43 void pushup(int rt,int len)//传入根节点以及右子区间的长度 
     44 {
     45     t[rt]=t[rt<<1]*p[len]+t[rt<<1|1];
     46 }
     47 void build(int l,int r,int rt)
     48 {
     49     if(l==r)
     50     {
     51         t[rt]=a[l]-'a'+1;
     52         return;
     53     }
     54     int mid=l+r>>1;
     55     build(lson);
     56     build(rson);
     57     pushup(rt,r-mid);
     58 }
     59 void update(int l,int r,int rt,int pos,char C)
     60 {
     61     if(l==r)
     62     {
     63         t[rt]=C-'a'+1;
     64         return;
     65     }
     66     int mid=l+r>>1;
     67     if(pos<=mid)update(lson,pos,C);
     68     else update(rson,pos,C);
     69     pushup(rt,r-mid);
     70 }
     71 ll query(int l,int r,int rt,int L,int R)
     72 {
     73     if(l>=L&&r<=R)//只有区间完全重合的时候取出hash值时不需要另加操作 
     74     {
     75         return t[rt];
     76     }
     77     int mid=l+r>>1;
     78     if(R<=mid) return query(lson,L,R);//分成三种情况,因为合并的时候需要乘系数 
     79     else if(L>mid) return query(rson,L,R);
     80     return  query(lson,L,mid)*p[R-mid]+query(rson,mid+1,R);
     81 }
     82 int main()
     83 {
     84     //freopen("input.txt","r",stdin);
     85     //freopen("output.txt","w",stdout);
     86     std::ios::sync_with_stdio(false);
     87     int tt;
     88     scan(tt);
     89     init();
     90     f(kk,1,tt)
     91     {
     92         set<ll> map;//字符串到hash值的映射表 
     93         scan(n);
     94         f(i,1,n)
     95         {
     96             scanf("%s",s);
     97             map.insert(gethash(s));
     98         }
     99         scanf("%s",a+1);
    100         int len=strlen(a+1);
    101         build(1,len,1);
    102         scan(m);
    103         char q[3];
    104         pf("Case #%d:
    ",kk); 
    105         while(m--)
    106         {
    107             
    108             scanf(" %s",q);
    109             if(q[0]=='Q')
    110             {
    111                 scan(x);
    112                 scan(y);
    113                 x++;//注意代码中线段树的左端点是从1开始的 
    114                 y++;
    115             //    dbg(query(1,len,1,x,y));
    116                 if(map.find(query(1,len,1,x,y))!=map.end())
    117                 pf("Yes
    ");
    118                 else pf("No
    ");
    119             }
    120             else if(q[0]=='C')
    121             {
    122                 char str[3];
    123                 scan(x);
    124                 x++;
    125                 scanf("%s",str);
    126                 update(1,len,1,x,str[0]);
    127             }
    128          } 
    129     }
    130  } 
  • 相关阅读:
    kafka搭建
    kafaka学习笔记
    metastore 简单说明
    二 python并发编程之多进程-理论
    文件指针偏移量
    FTP
    1 并发编程
    操作系统简介
    1 网络编程
    网络编程-osi七层
  • 原文地址:https://www.cnblogs.com/randy-lo/p/12444091.html
Copyright © 2020-2023  润新知