• ural 1989 subplindromes


    https://vjudge.net/problem/URAL-1989

    题意:

    先给出一个字符串,对于这个字符串,有两种操作,一种是询问从下标x到y的串是不是回文串,另一种是将下标为pos的字符改为另一种字符。

    思路:

    哎,看题解补的,还好学会了如何用hash判断回文串以及线段树单点更新在hash中的应用。

    下面来详细讲讲吧。

    首先,对于一个字符串,一共出现过n个不同的字符,那么就可以把这个字符串用n+1进制表示(考虑特殊元素0,比如bbaa,如果用26进制的话,那么就是1100,就会跟bb00起冲突,这一点要牢记)。因为这个n+1进制数表示为10进制数可能会很大,考虑无符号整型数,让其自然溢出,冲突的概率可以忽略不计(道听途说,这题反正没有问题)。

    在这题中,随时需要计算某个串的10进制表示,所以就需要把27^0,27^1,27^2……预处理出来,在计算的时候就是O(1)的复杂度。

    这题既然询问的是回文串,那么正向hash和反向hash都需要计算。之后,就用线段树来计算每一段字符串的hash值。当线段树建树的时候,递归到左右下标相等,那么此时就可以计算这个字符例如b的双向hash值,比如是字符串的长度是9,它的下标是3(注意字符串的下标从0开始,而线段树的最小下标是从1开始的),那么它的正向hash值就是000b,即为3 * (27) ^ 3,反向hash值就是00000b,即为 3 * (27) ^ 5。除了非真子树之外的其它节点的左hash,等于它的左儿子的左hash的值与右儿子的左hash的值的和,右hash类似。这样数就算建好了。

    之后我们查询的时候,按照线段树的方式来查询就好了,不过有一个要注意的地方,举一个例子,字符串的长度为8,abcdasde,查询的是2到5,即为bcda是否为回文串,但是此时通过查询得到的左hash值是0bcda,右hash值是000adcb,所以他们的位数实际是不相等的,这里我们就需要做进一步的处理使得他们的位数相等才能做比较,这时候需要把0bcda,向右移两位,变成000bcda,如何移位呢,这里其实跟2进制的位运算有异曲同工之妙的,直接乘27^(相差的0的个数),实际就是x-1和n-y的差的绝对值了。(这里自己举个例子就很明显了。)之后再比较左hash和右hash就ok了。

    更新的操作大概是这里面最简单的吧,不过不要忘记了向上更新的函数。

    代码:

      1 #include <stdio.h>
      2 #include <string.h>
      3 
      4 #define N 100005
      5 #define ll unsigned long long
      6 
      7 ll f[N];
      8 int n;
      9 
     10 struct tree
     11 {
     12     int l,r;
     13     ll suml,sumr;
     14 } tree[N << 2];
     15 
     16 char s[N];
     17 
     18 void pushup(int o)
     19 {
     20     tree[o].suml = tree[o << 1].suml + tree[o << 1|1].suml;
     21     tree[o].sumr = tree[o << 1].sumr + tree[o << 1|1].sumr;
     22 }
     23 
     24 void build(int o,int l,int r)
     25 {
     26     tree[o].l = l;
     27     tree[o].r = r;
     28 
     29     if (l == r)
     30     {
     31         tree[o].suml = f[l-1] * (s[l-1] - 'a');
     32         tree[o].sumr = f[n-l] * (s[l-1] - 'a');
     33         return;
     34     }
     35 
     36     int m = (l + r) >> 1;
     37 
     38     build(o << 1,l,m);
     39     build(o << 1 | 1,m+1,r);
     40 
     41     pushup(o);
     42 }
     43 
     44 ll suml,sumr;
     45 
     46 void query(int o,int l,int r)
     47 {
     48     if (tree[o].l >= l && tree[o].r <= r)
     49     {
     50         suml += tree[o].suml;
     51         sumr += tree[o].sumr;
     52 
     53         return;
     54     }
     55 
     56     int m = (tree[o].l + tree[o].r) >> 1;
     57 
     58     if (m >= l) query(o << 1,l,r);
     59     if (m < r) query(o << 1|1,l,r);
     60 }
     61 
     62 void update(int o,int pos,int c)
     63 {
     64     if (tree[o].l == tree[o].r)
     65     {
     66         tree[o].suml = f[pos-1] * c;
     67         tree[o].sumr = f[n-pos] * c;
     68 
     69         return;
     70     }
     71 
     72     int m = (tree[o].l + tree[o].r) >> 1;
     73 
     74     if (pos <= m) update(o << 1,pos,c);
     75     if (pos > m) update(o << 1|1,pos,c);
     76 
     77     pushup(o);
     78 }
     79 
     80 int main()
     81 {
     82     f[0] = 1;
     83 
     84     for (int i = 1;i < N;i++)
     85         f[i] = f[i-1] * 27;
     86 
     87     scanf("%s",s);
     88 
     89     n = strlen(s);
     90 
     91     build(1,1,n);
     92 
     93     int num;
     94 
     95     scanf("%d",&num);
     96 
     97     for (int i = 0;i < num;i++)
     98     {
     99         char a[50];
    100 
    101         scanf("%s",a);
    102 
    103         if (a[0] == 'p')
    104         {
    105             suml = sumr = 0;
    106 
    107             int x,y;
    108 
    109             scanf("%d%d",&x,&y);
    110 
    111             query(1,x,y);
    112 
    113             int d1 = x - 1;
    114             int d2 = n - y;
    115 
    116             if (d1 > d2) sumr *= f[d1-d2];
    117             else suml *= f[d2-d1];
    118 
    119             if (sumr == suml) printf("Yes
    ");
    120             else printf("No
    ");
    121         }
    122         else
    123         {
    124             char cc[10];
    125 
    126             int pos;
    127 
    128             scanf("%d%s",&pos,cc);
    129 
    130             update(1,pos,cc[0] - 'a');
    131         }
    132     }
    133 
    134     return 0;
    135 }
  • 相关阅读:
    Trie树详解及其应用
    最长回文字符串_Manacher算法_(O(n))
    设置VisualStudio以管理员身份运行
    wcf使用JetEntityFrameworkProvider.dll写access数据库时,报"操作必须使用一个可更新的查询"错误的解决办法
    data:image字符转byte[]
    ID为XXXX的进程当前未运行
    在Windows2003 server 64位系统上使用ArcEngine开发的WCF服务
    关于position的relative和absolute分别是相对于谁进行定位的
    sql语句进行写数据库时,字符串含有'的处理方式
    EF中关于日期字值的处理
  • 原文地址:https://www.cnblogs.com/kickit/p/7247592.html
Copyright © 2020-2023  润新知