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. 常用小技巧之PyCharm IDE

    Pycharm控制台窗口怎样可以显示不同程序的运行结果 默认情况下,每次运行会把之前的那个结果给清理掉. 有时候运行多个程序像对比结果,不太方便. 可以在pycharm的控制台那里点击右键,在弹出的菜 ...

  2. PTA(Advanced Level)1025.PAT Ranking

    To evaluate the performance of our first year CS majored students, we consider their grades of three ...

  3. check_mysql.sh

    #!/bin/bash# -------------------------------------------------------------------------------# FileNa ...

  4. 【记录】看见的一些很好的博客x存一下

    [字符串] AC自动机:https://www.cnblogs.com/cjyyb/p/7196308.html

  5. crm--rbac权限组件使用步骤

    本人的权限组件码云地址:https://gitee.com/shiguanggege/rbac 里面有文档详细介绍权限组件的使用步骤

  6. socket传送文件格式的问题

    在python3中socket传送文件只能传送‘bytes'类型,如下例子: import socket client = socket.socket()client.connect(("l ...

  7. Elastic Search的聚合搜索

    就是使用ES提供的aggs语法结果,使用DSL搜索的语法,实现聚合数据的统计,查询.ES中,如果新增document数据的时候,对应的index和type不存在,则自动创建. 1 准备源数据 PUT ...

  8. Docker——四种网络模式

    docker run创建Docker容器时,可以用–net选项指定容器的网络模式,Docker有以下4种网络模式:  bridge模式:使用–net =bridge指定,默认设置:  host模式 ...

  9. isEmpty 和 isBlank 区别

    isEmpty 和 isBlank 区别 org.apache.commons.lang.StringUtils 类提供了 String 的常用操作,最为常用的判空有如下两种 isEmpty(Stri ...

  10. pat L2-008 复习manacher

    马上要去比赛了 复习一下最长回文串的长度. 算法的实现两个步骤: 1. 一个是对原串的处理,在所有的空隙位置(包括首尾)插入同样的符号,要求这个符号是不会在原串中出现的.这样会使得所有的串都是奇数长度 ...