bzoj 1014 火星人prefix - 链表 - 分块
Description
火星人最近研究了一种操作:求一个字串两个后缀的公共前缀。比方说,有这样一个字符串: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函数的值。
Input
第一行给出初始的字符串。第二行是一个非负整数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不超过当前字符串长度
Output
对于输入文件中每一个询问操作,你都应该输出对应的答案。一个答案一行。
Sample Input
7
Q 1 7
Q 4 8
Q 10 11
R 3 a
Q 1 7
I 10 a
Q 2 11
Sample Output
1
0
2
1
HINT
1、所有字符串自始至终都只有小写字母构成。
2、M<=150,000
3、字符串长度L自始至终都满足L<=100,000
4、询问操作的个数不超过10,000个。
对于第1,2个数据,字符串长度自始至终都不超过1,000
对于第3,4,5个数据,没有插入操作。
题目大意 支持插入、修改字符,并且询问两个位置开始的最长公共前缀。
Solution 1 平衡树
用平衡树维护区间的Hash值,对于询问操作,二分答案,然后再区间查询check。
(比较懒,改天再写这个做法)
Solution 2 块状链表
对于普通的数组,插入最坏$O(n)$,对于普通的链表,插入最坏$O(n)$。
导致链表速度慢的原因是找到插入位置,导致数组插入慢的原因是挪动元素。
考虑一个数据就够能够解决这两个问题。
我们对链表进行分块就能很好地解决这个问题。
不过要注意一点:当块大小足够大时,需要分裂,否则会容易被卡。
对于这个问题,我的做法是如果插入的块满了,并且下一个块也满了才新开一块放溢出的元素。
现在考虑查询操作。
每一块维护前缀Hash值和后缀Hash值,然后每次考虑向前$\sqrt{L}$个元素,比较这一段的Hash值,如果它们相等就往前跳,如果不相等就一个字符一个字符地往前跳,直到某个字符不相等。
注意一个问题,就是查询的两个起始位置相等,特判一下就好。
然后注意插入的边界问题。
总时间复杂度$O(m\sqrt{L})$
(我本来天真地以为这个会比平衡树好写,然后我发现我想多了。。)
Code
/**
* bzoj
* Problem#1014
* Accepted
* Time: 3972ms
* Memory: 3824k
*/
#include <bits/stdc++.h>
using namespace std;
typedef bool boolean; const int cs = ;
const int base = ;
int powb[]; typedef class Chunk {
public:
Chunk *suf;
int s;
char str[cs + ];
int psh[cs + ];
int ssh[cs + ]; Chunk():suf(NULL), s() { }
Chunk(Chunk* org, int s):suf(org), s(s) { } static Chunk* alloc(); void maintain() {
psh[] = ssh[s + ] = ;
for(int i = ; i <= s; i++)
psh[i] = psh[i - ] + str[i] * powb[i - ];
for(int i = s; i; i--)
ssh[i] = ssh[i + ] * base + str[i];
} void insert(int p, char x) {
for(int i = s + ; i > p; i--)
str[i] = str[i - ];
str[p] = x;
if(full()) {
Chunk* nc = suf;
if(suf->full()) {
nc = alloc();
nc->suf = suf;
suf = nc;
}
nc->insert(, str[s + ]);
} else s++;
if(p <= s)
maintain();
} void modify(int p, char x) {
str[p] = x;
maintain();
} boolean full() {
return s == cs;
}
}Chunk; Chunk pool[];
Chunk *top = pool; Chunk* Chunk::alloc() {
return top++;
} typedef pair<Chunk*, int> pci;
#define fi first
#define sc second int m;
Chunk nsta = Chunk(&nsta, cs), nend = Chunk(&nend, cs);
char str[]; inline void init() {
nsta.suf = &nend;
powb[] = ;
for(int i = ; i <= ; i++)
powb[i] = powb[i - ] * base;
memset(nend.psh, -, sizeof(nend.psh)); gets(str + );
scanf("%d", &m); int fin = ;
Chunk* pc = &nsta, *nc;
while(str[fin]) {
nc = Chunk::alloc();
nc->suf = pc->suf;
pc->suf = nc;
for(nc->s = ; str[fin] && nc->s < cs; )
nc->str[++nc->s] = str[fin++];
nc->maintain();
pc = nc;
}
} pci findc(int pos) {
int skip = ;
pci rt(nsta.suf, );
while(skip + rt.fi->s < pos) {
skip += rt.fi->s;
rt.fi = rt.fi->suf;
}
rt.sc = pos - skip;
return rt;
} int getHash(pci p, pci& nxt) {
int skip = , rt = ;
rt = p.fi->ssh[p.sc];
skip = p.fi->s - p.sc + ;
p.fi = p.fi->suf;
while(skip + p.fi->s < cs) {
rt += powb[skip] * p.fi->psh[p.fi->s];
skip += p.fi->s;
p.fi = p.fi->suf;
}
nxt = pci(p.fi, cs - skip + );
if(nxt.sc > nxt.fi->s) {
nxt.sc -= nxt.fi->s;
nxt.fi = nxt.fi->suf;
}
rt += powb[skip] * p.fi->psh[cs - skip];
return rt;
} void getnext(pci &p) {
if(p.sc == p.fi->s)
p.sc = , p.fi = p.fi->suf;
else
p.sc++;
} void debugout() {
Chunk* p = nsta.suf;
while(p != &nend) {
puts(p->str + );
p = p->suf;
}
} inline void solve() {
char buf[];
int x, y, rt;
pci p1, p2, pn1, pn2;
// debugout();
while(m--) {
scanf("%s%d", buf, &x);
if(buf[] == 'Q') {
scanf("%d", &y);
if(x != y) {
rt = , p1 = findc(x), p2 = findc(y);
while(getHash(p1, pn1) == getHash(p2, pn2)) p1 = pn1, p2 = pn2, rt += cs;
while(p1.fi->str[p1.sc] == p2.fi->str[p2.sc]) {
getnext(p1);
getnext(p2);
rt++;
}
} else {
p1 = findc(x);
rt = p1.fi->s - p1.sc + ;
p1.fi = p1.fi->suf;
while(p1.fi != &nend) {
rt += p1.fi->s;
p1.fi = p1.fi->suf;
}
}
printf("%d\n", rt);
} else if(buf[] == 'R') {
scanf("%s", buf);
p1 = findc(x);
p1.fi->modify(p1.sc, buf[]);
} else {
scanf("%s", buf);
p2 = p1 = findc(x);
getnext(p1);
if(p1.fi != &nend)
p1.fi->insert(p1.sc, buf[]);
else
p2.fi->insert(p2.sc + , buf[]);
}
}
} int main() {
init();
solve();
return ;
}
bzoj 1014 火星人prefix - 链表 - 分块的更多相关文章
- BZOJ 1014 火星人prefix
Description 火星人最近研究了一种操作:求一个字串两个后缀的公共前缀.比方说,有这样一个字符串:madamimadam,我们将这个字符串的各个字符予以标号:序号: 1 2 3 4 5 6 7 ...
- [BZOJ]1014 火星人prefix(JSOI2008)
一边听省队dalao讲课一边做题真TM刺激. BZOJ的discuss简直就是题面plus.大样例.SuperHINT.dalao题解的结合体. Description 火星人最近研究了一种操作:求一 ...
- bzoj 1014 火星人prefix —— splay+hash
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1014 用 splay 维护字符串上不同位置的哈希值还是第一次... 具体就是每个节点作为位置 ...
- BZOJ 1014 火星人 | 平衡树维护哈希
BZOJ 1014 火星人 题意 有一个字符串,三中操作:在某位置后面插入一个字符.修改某位置的字符.询问两个后缀的最长公共前缀. 题解 看到网上的dalao们都说这道题是平衡树,我就很懵x--平衡树 ...
- 【BZOJ】【1014】【JLOI2008】火星人prefix
Splay/二分/Hash 看了网上的题目关键字(都不用点进去看……我也是醉了)了解到做法= =那就上呗,前面做了好几道Splay的题就是为了练手搞这个的. Hash判断字符串是否相同应该很好理解吧? ...
- BZOJ 1014: [JSOI2008]火星人prefix [splay 二分+hash] 【未完】
1014: [JSOI2008]火星人prefix Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 6243 Solved: 2007[Submit] ...
- BZOJ 1014: [JSOI2008]火星人prefix Splay+二分
1014: [JSOI2008]火星人prefix 题目连接: http://www.lydsy.com/JudgeOnline/problem.php?id=1014 Description 火星人 ...
- bzoj 1014: [JSOI2008]火星人prefix hash && splay
1014: [JSOI2008]火星人prefix Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 3154 Solved: 948[Submit][ ...
- 求帮看!!!!BZOJ 1014 [JSOI2008]火星人prefix
1014: [JSOI2008]火星人prefix Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 4164 Solved: 1277[Submit] ...
随机推荐
- cocos2d-x JS 开启远程代码调试
为了方便服务端与测试部门的工作需要,把客户端的写的程序可以在其他电脑上运行,方便他人工作与测试. 下面是cocos2d-x JS WebStorm 的设置方法.
- 笔记 : Ubuntu部署LNMP环境
一.准备与安装 1. 安装PHP7.1 #添加php源 :~$ sudo add-apt-repository ppa:ondrej/php #更新apt数据,载入php源数据 :~$ sudo ap ...
- JavaScript学习笔记之call和apply
前端的知识面太广了,想要记住所有知识点是不可能的,所以将这些学过的记录下来,随时都可以翻开来参考 1.call方法 调用一个对象的一个方法,call(this, arg1, arg2,argN);用来 ...
- jQuery-插入内容-新增内容
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- ModuleNotFoundError: No module named '_pydevd_bundle.pydevd_cython' error on debug
现象:pycharm调试代码出现错误:ModuleNotFoundError: No module named '_pydevd_bundle.pydevd_cython' error on debu ...
- Python2.6 升级2.7
一. Centos6 默认为python2.6且不可卸载(因为Centos6深度依赖Python),要想升级为2.7 只能通过全新升级 操作如下: 1.下载 Python2.7 网址 https:// ...
- IO model
上节的问题: 协程:遇到IO操作就切换. 但什么时候切回去呢?怎么确定IO操作完了? 很多程序员可能会考虑使用“线程池”或“连接池”.“线程池”旨在减少创建和销毁线程的频率,其维持一定合理数量的线程, ...
- SQL 中的连接查询
关于SQL的应用,肯定离不开查询,而相对复杂的查询,总是离不开对表的连接,单个表操作的并不罕见,但是在应用环境大多数的查询都是针对2.3个表甚至更多的表7,至于连接,有内连接.外链接.交叉连接之分,每 ...
- spring4.0.0 源码导入eclipse(sts)
其余步骤请见:http://www.cnblogs.com/xiluhua/p/7450972.html 执行 gradle eclipse -x :eclipse 报错: 解决办法: 找到 行,注释 ...
- MySQL 0Day漏洞出现 该漏洞可以拿到本地Root权限
2016年9月12日, legalhackers.com网站发布了编号为CVE-2016-6662的0day漏洞公告 .由于该漏洞可以获得MySQL服务器的Root权限,且影响MySql5.5.5.6 ...