【线段树哈希】「Balkan OI 2016」Haker
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的更多相关文章
- 线段树+哈希【CF580E】Kefa and Watch
线段树+哈希[CF580E]Kefa and Watch Description \(n\)个数的字符串,\(m + k\)个操作 1 l r k把\(l - r\)赋值为\(k\) 2 l r d询 ...
- 【博弈论】【SG函数】【线段树】Petrozavodsk Summer Training Camp 2016 Day 9: AtCoder Japanese Problems Selection, Thursday, September 1, 2016 Problem H. Cups and Beans
一开始有n个杯子,每个杯子里有一些豆子,两个人轮流操作,每次只能将一个豆子移动到其所在杯子之前的某个杯子里,不过可以移动到的范围只有一段区间.问你是否先手必胜. 一个杯子里的豆子全都等价的,因为sg函 ...
- 【线段树】Petrozavodsk Summer Training Camp 2016 Day 6: Warsaw U Contest, XVI Open Cup Onsite, Sunday, August 28, 2016 Problem H. Hay
有一些草,一开始高度都是0,它们的生长速率不同. 给你一些单增的日期,在这些日期要将>b的草的部分都割掉,问你每次割掉的部分有多少. 将草的生长速率从大到小排序,这样每次割掉的是一个后缀,而且不 ...
- Solution -「HEOI/TJOI 2016」「洛谷 P2824」排序
\(\mathcal{Description}\) Link. 给定排列 \(\{p_n\}\) 和 \(m\) 次局部排序操作,求操作完成后第 \(q\) 位的值. \(n,m\le10 ...
- UOJ #276「清华集训2016」汽水
为什么你们常数都这么小啊 UOJ #276 题意:在树上找一条链使得|边权平均值$ -k$|尽量小,$ n<=5e4$ $ Solution:$ 首先二分答案$ ans$,即我们需要找一条链使得 ...
- [LOJ#2743][DP]「JOI Open 2016」摩天大楼
题目传送门 DP 经典题 考虑从小到大把数加入排列内 如下图(\(A\) 已经经过排序): 我们考虑如上,在 \(i\) ( \(A_i\) )不断增大的过程中,维护上面直线 \(y=A_i\) 之下 ...
- [题解] [LOJ2743]「JOI Open 2016」摩天大楼
题目大意 将 \(N\) 个互不相同的整数 \(A_1 , A_2 , ⋯ , A_N\) 任意排列成 \(B_1 , B_2 , ⋯ , B_N\) . 要求 \(∑^{N−1}_{i=1} |B_ ...
- LOJ 2991 「THUSC 2016」补退选——trie+线段树合并或vector
题目:https://loj.ac/problem/2291 想了线段树合并的做法.就是用线段树维护 trie 的每个点在各种时间的操作. 然后线段树合并一番,线段树维护前缀最大值,就是维护最大子段和 ...
- LOJ 3066 - 「ROI 2016 Day2」快递(线段树合并+set 启发式合并)
LOJ 题面传送门 人傻常数大,需要狠命卡--/wq/wq 画个图可以发现两条路径相交无非以下两种情况(其中红色部分为两路径的重叠部分,粉色.绿色的部分分别表示两条路径): 考虑如何计算它们的贡献,对 ...
随机推荐
- vue 新闻列表滚动效果
效果如下: <template> <div> <div class="scroll-wrap"> <ul class="scro ...
- readline安装
wget -c ftp://ftp.gnu.org/gnu/readline/readline-6.2.tar.gz tar -zxvf readline-6.2.tar.gz cd readline ...
- Python之Web前端Ajax
Ajax: 对于WEB应用程序:用户浏览器发送请求,服务器接收并处理请求,然后返回结果,往往返回就是字符串(HTML),浏览器将字符串(HTML)渲染并显示浏览器上. 1.传统的Web应用 一个简单操 ...
- 理解twisted中的reactor和deferred(一)
Deferred是一个延迟加载对象,这个概念类似于tornado future,是调用异步操作返回的一个对象,其中包括了操作成功后的回调处理,错误后的回调处理. 简单讲,当我们需要执行一个耗时操作,比 ...
- Hive远程连接
HIVE的连接模式== 本地连接模式 直接启动hive命令 HIVE的远程连接 这里要启动HIVE的服务 thirft进行编写 hiveserver2 —- > 前台启动 后台启动 前台启动 h ...
- idea快捷生成
列模式: shift+alt+insert进入列选择模式,可选择一列或者多列 shift+alt+insert退出列选择模式 大小写转换: Ctrl + Shift + U 循环: iter 增强版 ...
- Swoft2.x 小白学习笔记 (一) ---控制器
Swoft通过官方文档进行学习,这里不做介绍,直接上手. 涉及到Swoft方面:(配置.注意的坑) 1.控制器(路由.验证器.中间件) 2.mysql (Model使用).Redis配置及通用池 3 ...
- python设计购物车
设计购物车 一需求: 1.启动程序后,输入用户名密码后,如果是第一次登录,让用户输入工资,然后打印商品列表 2.允许用户根据商品编号购买商品 3.用户选择商品后,检测余额是否够,够就直接扣款,不够就提 ...
- charles 抓包 (一)
在web.app开发中经常需要通过抓包来定位页面.接口返回数据的问题.在mac系统中,charles是一款功能丰富的抓包软件.可以实现app的数据抓包. 工具:charles 附送charles的破解 ...
- jquery选择器 模糊查找
$("input[class^='combo-text']").attr("readonly", "readonly"); 查找包含‘com ...