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了。

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

代码:

 #include <stdio.h>
#include <string.h> #define N 100005
#define ll unsigned long long ll f[N];
int n; struct tree
{
int l,r;
ll suml,sumr;
} tree[N << ]; char s[N]; void pushup(int o)
{
tree[o].suml = tree[o << ].suml + tree[o << |].suml;
tree[o].sumr = tree[o << ].sumr + tree[o << |].sumr;
} void build(int o,int l,int r)
{
tree[o].l = l;
tree[o].r = r; if (l == r)
{
tree[o].suml = f[l-] * (s[l-] - 'a');
tree[o].sumr = f[n-l] * (s[l-] - 'a');
return;
} int m = (l + r) >> ; build(o << ,l,m);
build(o << | ,m+,r); pushup(o);
} ll suml,sumr; void query(int o,int l,int r)
{
if (tree[o].l >= l && tree[o].r <= r)
{
suml += tree[o].suml;
sumr += tree[o].sumr; return;
} int m = (tree[o].l + tree[o].r) >> ; if (m >= l) query(o << ,l,r);
if (m < r) query(o << |,l,r);
} void update(int o,int pos,int c)
{
if (tree[o].l == tree[o].r)
{
tree[o].suml = f[pos-] * c;
tree[o].sumr = f[n-pos] * c; return;
} int m = (tree[o].l + tree[o].r) >> ; if (pos <= m) update(o << ,pos,c);
if (pos > m) update(o << |,pos,c); pushup(o);
} int main()
{
f[] = ; for (int i = ;i < N;i++)
f[i] = f[i-] * ; scanf("%s",s); n = strlen(s); build(,,n); int num; scanf("%d",&num); for (int i = ;i < num;i++)
{
char a[]; scanf("%s",a); if (a[] == 'p')
{
suml = sumr = ; int x,y; scanf("%d%d",&x,&y); query(,x,y); int d1 = x - ;
int d2 = n - y; if (d1 > d2) sumr *= f[d1-d2];
else suml *= f[d2-d1]; if (sumr == suml) printf("Yes\n");
else printf("No\n");
}
else
{
char cc[]; int pos; scanf("%d%s",&pos,cc); update(,pos,cc[] - 'a');
}
} return ;
}

ural 1989 subplindromes的更多相关文章

  1. N - Subpalindromes URAL - 1989 哈希+线段树

    N - Subpalindromes URAL - 1989 这个是一个哈希+线段树,这个题目也不算特别难,但是呢,还比较有意思. 这个题目给你两个操作,一个是回答l~r 区间是不是回文,一个是对一个 ...

  2. URAL 1989 Subpalindromes (多项式hash) +【线段树】

    <题目链接> <转载于 >>>  > 题目大意:给你一段字符串,进行两种操作:1.询问[l,r]这个区间中的字符串是否是回文串: 2.更改该字符串中对应下标的 ...

  3. 【URAL 1989】 Subpalindromes(线段树维护哈希)

    Description You have a string and queries of two types: replace i'th character of the string by char ...

  4. ural 1989(树状数组+多项式hash)

    题意:给出一个字符串.有两种操作,一个是p a b,问字符串从位置a到位置b的子串是否是一个回文子串.还有一个操作 c a b,把字符串位置a的字符替换为b. 题解:由于字符串长度为1e5且问的次数也 ...

  5. 线段树总结 (转载 里面有扫描线类 还有NotOnlySuccess线段树大神的地址)

    转载自:http://blog.csdn.net/shiqi_614/article/details/8228102 之前做了些线段树相关的题目,开学一段时间后,想着把它整理下,完成了大牛NotOnl ...

  6. 后缀数组 POJ 3974 Palindrome && URAL 1297 Palindrome

    题目链接 题意:求给定的字符串的最长回文子串 分析:做法是构造一个新的字符串是原字符串+反转后的原字符串(这样方便求两边回文的后缀的最长前缀),即newS = S + '$' + revS,枚举回文串 ...

  7. ural 2071. Juice Cocktails

    2071. Juice Cocktails Time limit: 1.0 secondMemory limit: 64 MB Once n Denchiks come to the bar and ...

  8. ural 2073. Log Files

    2073. Log Files Time limit: 1.0 secondMemory limit: 64 MB Nikolay has decided to become the best pro ...

  9. ural 2070. Interesting Numbers

    2070. Interesting Numbers Time limit: 2.0 secondMemory limit: 64 MB Nikolay and Asya investigate int ...

随机推荐

  1. 记一次调试串口设备Bug的经历

    最近花了差不多1天的时间在折腾一个Bug,该Bug的表象如下: 这个Bug还特别独特,在开发电脑中无提示,在终端用户那里每次使用软件的时候都报这个.仔细思考了一下最近在源码中新添加的功能,没发现有啥特 ...

  2. java入门学习笔记之1(类的定义,代码的编译执行)

    这篇文章讲解Java代码的基本执行过程 我们先抛开各种JAVA IDE,开发工具,只使用文本编辑器,以突出最本质的东西. 在Linux环境下,我们编辑一个文件: vim HelloWorld.java ...

  3. “前”方有坑,绕道而行(一)-- H5+CSS

    1. 关于  数字.英文 不换行问题: 情景:昨天测试 小程序,输入英文,没有换行,且 下方有横向滚动条: 解决:word-break: word-break:break-all; /*只对英文起作用 ...

  4. JVM中class文件探索与解析(一)

    一直想成为一名优秀的架构师的我,转眼已经工作快两年了,对于java内核了解甚少,闲来时间,看看JVM,吧自己的一些研究写下来供大家参考,有不对的地方请指正. 废话不多说,一起来看看JVM中类文件是如何 ...

  5. Streaming输入输出

    Structured Streaming 输入输出 输入 SparkSession.readStream() 返回一个 DataStreamReader 接口对象,可以通过该对象对输入源进行参数配置, ...

  6. 在jupyter notebook中同时安装python2和python3

    之前讨论过在anaconda下安装多个python版本,本期来讨论下,jupyter notebook中怎样同时安装python2.7 和python3.x. 由于我之前使用的jupyter note ...

  7. 2.如何使用matlab拟合曲线

    输入数据 做数据曲线拟合,当然该有数据,本经验从以如下数据作为案例.   添加数据到curve fitting程序 这一步就是将你要拟合的数据添加到curve fitting程序中,同时给你拟合的曲线 ...

  8. ==,=和equals()区别

    equals和=,==的区别   一. ==和equals的区别 1. ==是运算符 2. equals是String对象的方法 一般有两种类型的比较 1. 基本数据类型的比较 2. 引用对象的比较 ...

  9. C#窗体多语言切换(简繁)

    多窗体最好继承一个父窗体,在父窗体Load事件中执行此方法 添加引用 using Microsoft.VisualBasic; #region 语言切换 /// <summary> /// ...

  10. LR监控Windows Server 2008 R2系统资源提示“指定的网络名不可用。”

    问题现象: LR监控远程服务器Window Server 2008 R2 系统资源,提示“Monitor name :Windows Resources. Cannot connect to mach ...