1A海星

题目大意

给你一个长度为 $n$ ,由小写字母构成的字符串 $S$ 和 $Q$ 个操作,每个操作是以下 3 种之一:

  • 1 x y k :询问当前字符串从位置 $x$ 到 $y$ 的子串与从位置 $k$ 开始,长度为 $y-x+1$ 的子串是否相同。
  • 2 x y k :将当前字符串从位置 $x$ 到 $y$ 的子串变成原始串从位置 $k$ 开始,长度为 $y−x+1$ 的子串。
  • 3 x y :将当前字符串从位置 $x$ 到 $y$ 的子串中的所有 $a$ 变成 $b$ ,$b$ 变成 $c$ ,$\cdots $ ,$z$ 变成 $a$ 。

$n,q \le 10^5$


题目分析

初一看前两个操作用字符串哈希都可以轻松解决,比较难处理的是这个操作3循环位移。

如果一直只想着对字符按顺序哈希这一种狭隘的哈希,这个循环位移是没法处理的。那么从其他角度考虑,由于循环位移涉及到两个不同质字符的 交换,所以应该记录一些只关于一种同质字符的信息——它的出现位置。也就是说对它的出现位置哈希,从而实现循环位移,而比较相同只需要将$|\sum|$个字符的出现位置都比较一次就可以了。

对出现位置哈希还有一个好处就是可以处理 形式相同(即按最小表示法相同)的字符串比较。

这题另外一种变式就是把操作2改成:“将当前字符串从位置 $x$ 到 $y$ 的子串变成 当前串 从位置 $k$ 开始,长度为 $y−x+1$ 的子串”。那这个相当于是覆盖为历史版本的线段树上哈希值,可持久化一下应该就可以了。

只写了最简单的原题版本。

 #include<bits/stdc++.h>
typedef unsigned int uint;
const int maxn = ;
const uint base = ; struct node
{
uint val[];
int tag,rnd;
}f[maxn<<];
int n,m;
char s[maxn];
uint hsh[maxn][],pwr[maxn],retx[],rety[]; inline char nc(){
static char buf[],*p1=buf,*p2=buf;
return p1==p2 && (p2=(p1=buf)+fread(buf,,,stdin),p1==p2)?EOF:*p1++;
}
#define getchar nc
int read()
{
char ch = getchar();
int num = , fl = ;
for (; !isdigit(ch); ch=getchar())
if (ch=='-') fl = -;
for (; isdigit(ch); ch=getchar())
num = (num<<)+(num<<)+ch-;
return num*fl;
}
uint hash(int i, int l, int r)
{
return hsh[r][i]-hsh[l-][i]*pwr[r-l+];
}
void build(int rt, int l, int r)
{
f[rt].tag = -, f[rt].rnd = ;
for (int i=; i<=; i++) f[rt].val[i] = hash(i, l, r);
if (l==r) return;
int mid = (l+r)>>;
build(rt<<, l, mid);
build(rt<<|, mid+, r);
}
void round(int rt)
{
for (int i=; i>=; i--)
f[rt].val[i] = f[rt].val[i-];
f[rt].val[] = f[rt].val[];
}
void pushdown(int rt, int l, int mid, int r)
{
if (f[rt].tag!=-){
f[rt<<].tag = f[rt].tag, f[rt<<|].tag = f[rt].tag+mid-l+, f[rt].tag = -;
f[rt<<].rnd = , f[rt<<|].rnd = ;
for (int i=; i<=; i++)
f[rt<<].val[i] = hash(i, f[rt<<].tag, f[rt<<].tag+mid-l),
f[rt<<|].val[i] = hash(i, f[rt<<|].tag, f[rt<<|].tag+r-mid-);
}
f[rt<<].rnd += f[rt].rnd, f[rt<<|].rnd += f[rt].rnd;
for (int i=; i<=f[rt].rnd; i++) round(rt<<), round(rt<<|);
f[rt].rnd = ; }
void query(int rt, int l, int r, int L, int R, uint *ret)
{
if (L <= l&&r <= R){
for (int i=; i<=; i++) ret[i] = ret[i]*pwr[r-l+]+f[rt].val[i];
}else{
int mid = (l+r)>>;
pushdown(rt, l, mid, r);
if (L <= mid) query(rt<<, l, mid, L, R, ret);
if (R > mid) query(rt<<|, mid+, r, L, R, ret);
}
}
void addtag(int rt, int l, int r, int L, int R, int k)
{
if (L <= l&&r <= R){
f[rt].tag = k+l-L, f[rt].rnd = ;
for (int i=; i<=; i++)
f[rt].val[i] = hash(i, k+l-L, k+r-L);
}else{
int mid = (l+r)>>;
pushdown(rt, l, mid, r);
if (L <= mid) addtag(rt<<, l, mid, L, R, k);
if (R > mid) addtag(rt<<|, mid+, r, L, R, k);
}
}
void circulation(int rt, int l, int r, int L, int R)
{
if (L <= l&&r <= R) ++f[rt].rnd, round(rt);
else{
int mid = (l+r)>>;
pushdown(rt, l, mid, r);
if (L <= mid) circulation(rt<<, l, mid, L, R);
if (R > mid) circulation(rt<<|, mid+, r, L, R);
}
}
int main()
{
scanf("%s",s+);
n = strlen(s+), m = read(), pwr[] = ;
for (int i=; i<=n; i++)
{
pwr[i] = pwr[i-]*base;
for (int j=; j<=; j++) hsh[i][j] = hsh[i-][j]*base+(j==s[i]-'a'+);
}
build(, , n);
for (int i=; i<=m; i++)
{
int opt = read();
if (opt==){
int x = read(), y = read(), k = read();
for (int i=; i<=; i++) retx[i] = rety[i] = ;
query(, , n, x, y, retx);
query(, , n, k, k+y-x, rety);
bool legal = true;
for (int i=; i<=&&legal; i++)
if (retx[i]!=rety[i]) legal = false;
puts(legal?"Y":"N");
}else if (opt==){
int x = read(), y = read(), k = read();
addtag(, , n, x, y, k);
}else{
int x = read(), y = read();
circulation(, , n, x, y);
}
}
return ;
}

END

【线段树哈希】「Balkan OI 2016」Haker的更多相关文章

  1. 线段树+哈希【CF580E】Kefa and Watch

    线段树+哈希[CF580E]Kefa and Watch Description \(n\)个数的字符串,\(m + k\)个操作 1 l r k把\(l - r\)赋值为\(k\) 2 l r d询 ...

  2. 【博弈论】【SG函数】【线段树】Petrozavodsk Summer Training Camp 2016 Day 9: AtCoder Japanese Problems Selection, Thursday, September 1, 2016 Problem H. Cups and Beans

    一开始有n个杯子,每个杯子里有一些豆子,两个人轮流操作,每次只能将一个豆子移动到其所在杯子之前的某个杯子里,不过可以移动到的范围只有一段区间.问你是否先手必胜. 一个杯子里的豆子全都等价的,因为sg函 ...

  3. 【线段树】Petrozavodsk Summer Training Camp 2016 Day 6: Warsaw U Contest, XVI Open Cup Onsite, Sunday, August 28, 2016 Problem H. Hay

    有一些草,一开始高度都是0,它们的生长速率不同. 给你一些单增的日期,在这些日期要将>b的草的部分都割掉,问你每次割掉的部分有多少. 将草的生长速率从大到小排序,这样每次割掉的是一个后缀,而且不 ...

  4. Solution -「HEOI/TJOI 2016」「洛谷 P2824」排序

    \(\mathcal{Description}\)   Link.   给定排列 \(\{p_n\}\) 和 \(m\) 次局部排序操作,求操作完成后第 \(q\) 位的值.   \(n,m\le10 ...

  5. UOJ #276「清华集训2016」汽水

    为什么你们常数都这么小啊 UOJ #276 题意:在树上找一条链使得|边权平均值$ -k$|尽量小,$ n<=5e4$ $ Solution:$ 首先二分答案$ ans$,即我们需要找一条链使得 ...

  6. [LOJ#2743][DP]「JOI Open 2016」摩天大楼

    题目传送门 DP 经典题 考虑从小到大把数加入排列内 如下图(\(A\) 已经经过排序): 我们考虑如上,在 \(i\) ( \(A_i\) )不断增大的过程中,维护上面直线 \(y=A_i\) 之下 ...

  7. [题解] [LOJ2743]「JOI Open 2016」摩天大楼

    题目大意 将 \(N\) 个互不相同的整数 \(A_1 , A_2 , ⋯ , A_N\) 任意排列成 \(B_1 , B_2 , ⋯ , B_N\) . 要求 \(∑^{N−1}_{i=1} |B_ ...

  8. LOJ 2991 「THUSC 2016」补退选——trie+线段树合并或vector

    题目:https://loj.ac/problem/2291 想了线段树合并的做法.就是用线段树维护 trie 的每个点在各种时间的操作. 然后线段树合并一番,线段树维护前缀最大值,就是维护最大子段和 ...

  9. LOJ 3066 - 「ROI 2016 Day2」快递(线段树合并+set 启发式合并)

    LOJ 题面传送门 人傻常数大,需要狠命卡--/wq/wq 画个图可以发现两条路径相交无非以下两种情况(其中红色部分为两路径的重叠部分,粉色.绿色的部分分别表示两条路径): 考虑如何计算它们的贡献,对 ...

随机推荐

  1. Hive概述

    HIVE是什么    开发调试麻烦    只能用java开发     需要对hadoop的底层及api比较了解才能开发复杂代码 HQL Hive是基于Hadoop的一个数据仓库工具.可以将结构化的数据 ...

  2. golang break label 与goto label

    本文链接:https://blog.csdn.net/itbsl/article/details/73380537 与其他语言一样,Go语言也支持label(标签)语法:分别是break label和 ...

  3. 2017Nowcoder Girl初赛重现赛 D(二进制枚举

    链接:https://ac.nowcoder.com/acm/contest/315/D来源:牛客网 题目描述 妞妞参加完Google Girl Hackathon之后,打车回到了牛家庄. 妞妞需要支 ...

  4. xml 表格

    设置单元格样式 <Style ss:ID="唯一id字符" ss:Name="单元格样式"> [内部通常用来设置 Alignment对齐.Font字 ...

  5. Spring 注解介绍

    @Component与@Bean的区别 @Component注解表明一个类会作为组件类,并告知Spring要为这个类创建bean. @Bean注解告诉Spring这个方法将会返回一个对象,这个对象要注 ...

  6. Spring MVC(一)Spring MVC的原理

    1.Spring MVC的目的 构建像Spring框架那样灵活和松耦合的Web应用程序. 2.Spring MVC中如何处理Request? 每当用户在Web浏览器中点击链接或者提交表单时,Reque ...

  7. 怎样理解Node对象接口

    dom中的节点都继承自Node接口, 也就是说, 所有的节点都具有Node接口所规定的属性和方法, 比如下面这个 <a> 标签, 它也继承了Node的所有属性和方法: 可以认为Node接口 ...

  8. java——HashSet类中的常见方法

    package com.xt.set; import java.util.HashSet; import java.util.Iterator; import java.util.Set; publi ...

  9. 【weixin】微信支付---Native支付模式二(PC端支付大多采用此模式)

    [模式二]:商户后台系统调用微信支付[统一下单API]生成预付交易,将接口返回的链接生成二维码,用户扫码后输入密码完成支付交易.注意:该模式的预付单有效期为2小时,过期后无法支付 模式二与模式一相比, ...

  10. [转载]Yacc基础

    原文:https://www.ibm.com/developerworks/cn/linux/sdk/lex/index.html,摘录部分内容. Yacc的定义 Yacc 代表 Yet Anothe ...