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. PyQt5环境搭建及cx_freeze打包exe

    Python的图形库也有好几个,Qt文档和使用面还是要广一些. 打包成可执行文件的也有好几个,PyInstaller用的比较多,但是PyInstaller目前还不支持Python3.6(开发版支持3. ...

  2. python爬虫番外篇(一)进程,线程的初步了解

    一.进程 程序并不能单独和运行只有将程序装载到内存中,系统为他分配资源才能运行,而这种执行的程序就称之为进程.程序和进程的区别在于:程序是指令的集合,它是进程的静态描述文本:进程是程序的一次执行活动, ...

  3. zookeeper 应用场景概述

    Zookeeper主要可以干哪些事情:配置管理,名字服务,提供分布式同步以及集群管理. 一 .配置管理 在我们的应用中除了代码外,还有一些就是各种配置.比如数据库连接,远程服务访问地址等.一般我们都是 ...

  4. 【原创】源码角度分析Android的消息机制系列(三)——ThreadLocal的工作原理

    ι 版权声明:本文为博主原创文章,未经博主允许不得转载. 先看Android源码(API24)中对ThreadLocal的定义: public class ThreadLocal<T> 即 ...

  5. 高性能队列Disruptor系列2--浅析Disruptor

    1. Disruptor简单介绍 Disruptor是一个由LMAX开源的Java并发框架.LMAX是一种新型零售金融交易平台,这个系统是建立在 JVM 平台上,核心是一个业务逻辑处理器,它能够在一个 ...

  6. winform / Dev全局皮肤组件

    话不多说先上效果图. 由于这是单独的测试项目, 用于演示Dev控件的皮肤样式, 所以上面只是演示了部分控件的效果. 下面则是一些实际项目中的截图: Dev的控件样式不仅美观丰富, 上面仅皮肤设置就有4 ...

  7. flask 扩展之 -- flask-moment

    一. 安装 $ pip install flask-moment 二. 初始化 from flask_moment import Moment moment = Moment(app) 三. 解决依赖 ...

  8. HTML行内元素、块状元素、行内块状元素的区别

    HTML可以将元素分类方式分为行内元素.块状元素和行内块状元素三种.首先需要说明的是,这三者是可以互相转换的,使用display属性能够将三者任意转换: (1)display:inline;转换为行内 ...

  9. Vue.js 介绍入门

    Vue.js 的目标 是通过尽可能简单的 API 实现响应的数据绑定和组合的视图组件.Vue.js 是一个用于创建 Web 交互界面的库.它让你通过简单而灵活的 API 创建由数据驱动的 UI 组件. ...

  10. window.onload的加载和$(document).read()

    1.执行时机: window.onload :必须等到网页中所有的内容加载完之后才执行. $(document).read():网页中所有的DOM结构执行完毕后.可能DOM元素并未加载完. 2.单个网 ...