[BZOJ1014][JSOI2008]火星人prefix

试题描述

火星人最近研究了一种操作:求一个字串两个后缀的公共前缀。比方说,有这样一个字符串:madamimadam,
我们将这个字符串的各个字符予以标号:序号: 1 2 3 4 5 6 7 8 9 10 11 字符 m a d a m i m a d a m 现在,
火星人定义了一个函数LCQ(x, y),表示:该字符串中第x个字符开始的字串,与该字符串中第y个字符开始的字串
,两个字串的公共前缀的长度。比方说,LCQ(1, 7) = 5, LCQ(2, 10) = 1, LCQ(4, 7) = 0 在研究LCQ函数的过程
中,火星人发现了这样的一个关联:如果把该字符串的所有后缀排好序,就可以很快地求出LCQ函数的值;同样,
如果求出了LCQ函数的值,也可以很快地将该字符串的后缀排好序。 尽管火星人聪明地找到了求取LCQ函数的快速
算法,但不甘心认输的地球人又给火星人出了个难题:在求取LCQ函数的同时,还可以改变字符串本身。具体地说
,可以更改字符串中某一个字符的值,也可以在字符串中的某一个位置插入一个字符。地球人想考验一下,在如此
复杂的问题中,火星人是否还能够做到很快地求取LCQ函数的值。

输入

第一行给出初始的字符串。第二行是一个非负整数M,表示操作的个数。接下来的M行,每行描述一个操作。操
作有3种,如下所示
1、询问。语法:Qxy,x,y均为正整数。功能:计算LCQ(x,y)限制:1<=x,y<=当前字符串长度。
2、修改。语法:Rxd,x是正整数,d是字符。功能:将字符串中第x个数修改为字符d。限制:x不超过当前字
符串长度。
3、插入:语法:Ixd,x是非负整数,d是字符。功能:在字符串第x个字符之后插入字符d,如果x=0,则在字
符串开头插入。限制:x不超过当前字符串长度

输出

对于输入文件中每一个询问操作,你都应该输出对应的答案。一个答案一行。

输入示例

madamimadam

Q
Q
Q
R a
Q
I a
Q

输出示例


数据规模及约定

1、所有字符串自始至终都只有小写字母构成。
2、M<=150,000
3、字符串长度L自始至终都满足L<=100,000
4、询问操作的个数不超过10,000个。
对于第1,2个数据,字符串长度自始至终都不超过1,000
对于第3,4,5个数据,没有插入操作。

题解

用 splay 维护 hash 值,查询时二分一下。

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <algorithm>
using namespace std; int read() {
int x = 0, f = 1; char c = getchar();
while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); }
while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); }
return x * f;
} #define maxn 100010
#define UL unsigned int
struct Node {
char c; int siz; UL h[2];
Node() {}
Node(char _): c(_) {}
} ns[maxn];
int ToT, fa[maxn], ch[maxn][2]; char in_S[maxn];
UL idx[maxn][2];
void maintain(int o) {
ns[o].siz = 1;
for(int i = 0; i < 2; i++) if(ch[o][i])
ns[o].siz += ns[ch[o][i]].siz;
int rs = ch[o][1] ? ns[ch[o][1]].siz : 0;
for(int i = 0; i < 2; i++) {
UL& tmp = ns[o].h[i]; tmp = 0;
if(ch[o][1]) tmp += ns[ch[o][1]].h[i];
tmp += idx[rs][i] * (UL)ns[o].c;
if(ch[o][0]) tmp += idx[rs+1][i] * ns[ch[o][0]].h[i];
}
return ;
}
void build(int& o, int l, int r) {
if(l > r) return ;
int mid = l + r >> 1; ns[o = mid] = Node(in_S[mid]);
build(ch[o][0], l, mid - 1); build(ch[o][1], mid + 1, r);
if(ch[o][0]) fa[ch[o][0]] = o;
if(ch[o][1]) fa[ch[o][1]] = o;
return maintain(o);
}
void rotate(int u) {
int y = fa[u], z = fa[y], l = 0, r = 1;
if(z) ch[z][ch[z][1]==y] = u;
if(ch[y][1] == u) swap(l, r);
fa[u] = z; fa[y] = u; fa[ch[u][r]] = y;
ch[y][l] = ch[u][r]; ch[u][r] = y;
maintain(y); maintain(u);
return ;
}
void splay(int u) {
while(fa[u]) {
int y = fa[u], z = fa[y];
if(z) {
if(ch[y][0] == u ^ ch[z][0] == y) rotate(u);
else rotate(y);
}
rotate(u);
}
return ;
}
int getrt() {
int u = 1; while(fa[u]) u = fa[u];
return u;
}
int Find(int o, int k) {
if(!o) return 0;
int ls = ch[o][0] ? ns[ch[o][0]].siz : 0;
if(k == ls + 1) return o;
if(k > ls + 1) return Find(ch[o][1], k - ls - 1);
return Find(ch[o][0], k);
}
int split(int u) {
if(!u) {
u = Find(getrt(), 1); splay(u);
return u;
}
splay(u);
int tmp = ch[u][1];
fa[tmp] = ch[u][1] = 0;
return maintain(u), tmp;
}
int merge(int a, int b) {
if(!a) return maintain(b), b;
while(ch[a][1]) a = ch[a][1];
splay(a);
ch[a][1] = b; fa[b] = a;
return maintain(a), a;
}
void geths(int ql, int qr, UL& h1, UL& h2) {
int tt = getrt(), lrt = Find(tt, ql - 1), mrt = Find(tt, qr), rrt;
split(lrt); rrt = split(mrt);
// printf("geths: %c %c\n", lrt ? ns[lrt].c : '-', ns[mrt].c);
h1 = ns[mrt].h[0]; h2 = ns[mrt].h[1];
mrt = merge(lrt, mrt); merge(mrt, rrt);
return ;
}
void insert(int p, char c) {
int lrt = Find(getrt(), p), mrt, rrt = split(lrt);
ns[mrt = ++ToT] = Node(c); maintain(mrt);
mrt = merge(lrt, mrt); merge(mrt, rrt);
return ;
} int main() {
idx[0][0] = idx[0][1] = 1;
for(int i = 1; i < maxn; i++) idx[i][0] = idx[i-1][0] * 233, idx[i][1] = idx[i-1][1] * 666;
scanf("%s", in_S + 1); ToT = strlen(in_S + 1);
int rt = 0; build(rt, 1, ToT);
int q = read();
while(q--) {
char tp[2]; scanf("%s", tp);
if(tp[0] == 'Q') {
int x = read(), y = read(), l = 0, r = ToT - max(x, y) + 2;
while(r - l > 1) {
int mid = l + r >> 1;
UL h11, h12, h21, h22;
geths(x, x + mid - 1, h11, h12);
geths(y, y + mid - 1, h21, h22);
// printf("%d %u %u %u %u\n", mid, h11, h21, h12, h22);
if(h11 == h21 && h12 == h22) l = mid; else r = mid;
}
printf("%d\n", l);
}
if(tp[0] == 'R') {
int x = Find(getrt(), read()); char tmp[2]; scanf("%s", tmp);
ns[x].c = tmp[0];
while(fa[x]) maintain(x), x = fa[x]; maintain(x);
}
if(tp[0] == 'I') {
int x = read(); char tmp[2]; scanf("%s", tmp);
insert(x, tmp[0]);
}
} return 0;
}

[BZOJ1014][JSOI2008]火星人prefix的更多相关文章

  1. BZOJ1014 JSOI2008 火星人prefix 【非旋转Treap】*

    BZOJ1014 JSOI2008 火星人prefix Description 火星人最近研究了一种操作:求一个字串两个后缀的公共前缀.比方说,有这样一个字符串:madamimadam,我们将这个字符 ...

  2. 2018.06.28 BZOJ1014 [JSOI2008]火星人prefix(非旋treap+hash)

    [JSOI2008]火星人prefix Time Limit: 10 Sec Memory Limit: 162 MB Submit: 8951 Solved: 2860 Description 火星 ...

  3. bzoj千题计划106:bzoj1014 [JSOI2008]火星人prefix

    http://www.lydsy.com/JudgeOnline/problem.php?id=1014 两个后缀的最长公共前缀:二分+hash 带修改带插入:splay维护 #include< ...

  4. [BZOJ1014] [JSOI2008] 火星人prefix (splay & 二分答案)

    Description 火星人最近研究了一种操作:求一个字串两个后缀的公共前缀.比方说,有这样一个字符串:madamimadam,我们将这个字符串的各个字符予以标号:序号: 1 2 3 4 5 6 7 ...

  5. bzoj1014: [JSOI2008]火星人prefix splay+hash+二分

    Description 火星人最近研究了一种操作:求一个字串两个后缀的公共前缀.比方说,有这样一个字符串:madamimadam,我们将这个字符串的各个字符予以标号:序号: 1 2 3 4 5 6 7 ...

  6. [bzoj1014](JSOI2008)火星人 prefix (Splay维护哈希)

    Description 火星人最近研究了一种操作:求一个字串两个后缀的公共前缀. 比方说,有这样一个字符串:madamimadam,我们将这个字符串的各个字符予以标号:序号: 1 2 3 4 5 6 ...

  7. BZOJ1014[JSOI2008]火星人prefix(splay维护hash)

    Description 火星人最近研究了一种操作:求一个字串两个后缀的公共前缀.比方说,有这样一个字符串:madamimadam,我们将这个字符串的各个字符予以标号:序号: 1 2 3 4 5 6 7 ...

  8. BZOJ1014: [JSOI2008]火星人prefix(splay 二分 hash)

    题意 题目链接 Sol 一眼splay + 二分hash,不过区间splay怎么写来着呀 试着写了两个小时发现死活不对 看了一下yyb的代码发现自己根本就不会splay.... // luogu-ju ...

  9. bzoj1014: [JSOI2008]火星人prefix(splay+hash+二分)

    题目大意:一个字符串三个操作:①求两个后缀的LCP②插入一个字符③修改一个字符. 前几天刚学了hash+二分求lcp,就看到这题. 原来splay还能这么用?!原来splay模板这么好写?我以前写的s ...

随机推荐

  1. GO语言总结(4)——映射(Map)

    上一篇博客介绍了Go语言的数组和切片——GO语言总结(3)——数组和切片,本篇博客介绍Go语言的映射(Map) 映射是一种内置的数据结构,用来保存键值对的无序集合. (1)映射的创建 make ( m ...

  2. Ubuntu apache2.4 设置虚拟主机

    每次重装系统如何配置都上网找,搞半天,都是不对的,还不如自己记下来,以作参考呢.我的项目目录是 /home/feiffy/demo/test,映射的域名是 test.com,这样在浏览器输入 test ...

  3. 协程--gevent模块(单线程高并发)

    先恶补一下知识点,上节回顾 上下文切换:当CPU从执行一个线程切换到执行另外一个线程的时候,它需要先存储当前线程的本地的数据,程序指针等,然后载入另一个线程的本地数据,程序指针等,最后才开始执行.这种 ...

  4. 关于SQL注入和如何防止

    之前在笔试的时候没有很好的答出这个问题,因此我要总结一下问题,以免日后继续在这个地方跌倒,以下是自己的理解,如有错误请指出 一.什么是SQL注入 SQL注入就是服务器在根据业务去处理数据库的时候,客户 ...

  5. 【bzoj4008】 HNOI2015—亚瑟王

    http://www.lydsy.com/JudgeOnline/problem.php?id=4008 (题目链接) 题意 给出n个技能,每个技能按顺序有p[i]的可能性释放,可以造成d[i]的伤害 ...

  6. CUDA[2] Hello,World

    Section 0:Hello,World 这次我们亲自尝试一下如何用粗(CU)大(DA)写程序 CUDA最新版本是7.5,然而即使是最新版本也不兼容VS2015 ...推荐使用VS2012 进入VS ...

  7. Linux CentOS6.x ip设置(网卡设置)

    修改IP永久生效按以下方法vi /etc/sysconfig/network-scripts/ifcfg-eth0(eth0,第一块网卡,如果是第二块则为eth1)按如下修改ip: DEVICE=et ...

  8. Codeforces 划水

    Codeforces 566F 题目大意:给定$N$个数,任意两个数之间若存在一个数为另一个数的因数,那么这两个数存在边,求图中最大团. 分析:求一个图最大团为NP-Hard问题,一般不采用硬方法算. ...

  9. Python 编码简单说

    先说说什么是编码. 编码(encoding)就是把一个字符映射到计算机底层使用的二进制码.编码方案(encoding scheme)规定了字符串是如何编码的. python编码,其实就是对python ...

  10. HTTP 基础知识

    HTTP是一种协议.HTTP使用流程,一般情况下, 第一:由HTTP客户端发出请求,创建端口. 第二:HTTP服务器在端口监听客户端的请求. 第三:一旦收到请求,HTTP服务器向客户端返回状态和内容. ...