【bzoj1014】[JSOI2008]火星人prefix
1014: [JSOI2008]火星人prefix
Time Limit: 10 Sec Memory Limit: 162 MB
Submit: 6031 Solved: 1917
[Submit][Status][Discuss]
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个数据,没有插入操作。
【题解】
用splay维护字符串,把一段子串用哈希值表示,两个长度相同的子串如果哈希值相同,那么它们就相同。
建树时每棵子树的哈希值集中在根节点上,即h[x]=(h[left[x]]+v[x]*p[size[left]]+h[r]*p[size[left]+1])%mod
查询时二分一个答案,然后验证。
那么如何找到子串的哈希值呢?
首先找到子串的首字母,把它伸展到根,然后找到子串的尾字母的下一个字母,把它伸展到根的右儿子,那么根的右儿子的左儿子的哈希值就是答案。
吐槽:这题交了很多遍,都是RE,然后我才知道BZOJ上用cin会RE......
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<ctime>
#include<algorithm>
using namespace std;
#define MAXN 150010
#define ll long long
#define mod 9875321
int n,m,rt,sz,p[MAXN],c[MAXN][],fa[MAXN],size[MAXN],h[MAXN],v[MAXN];
char ch[MAXN];
namespace INIT
{
inline int read()
{
int x=,f=; char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-; ch=getchar();}
while(isdigit(ch)) {x=x*+ch-''; ch=getchar();}
return x*f;
}
}using namespace INIT;
namespace SPLAY
{
void updata(int x)
{
int l=c[x][],r=c[x][];
size[x]=size[l]+size[r]+;
h[x]=h[l]+(ll)v[x]*p[size[l]]%mod+(ll)p[size[l]+]*h[r]%mod;
h[x]%=mod;
}
void rotate(int x,int &k)
{
int y=fa[x],z=fa[y],l,r;
if(c[y][]==x) l=; else l=; r=l^;
if(y==k) k=x;
else {if(c[z][]==y) c[z][]=x; else c[z][]=x;}
fa[x]=z; fa[y]=x; fa[c[x][r]]=y;
c[y][l]=c[x][r]; c[x][r]=y;
updata(y); updata(x);
}
void Splay(int x,int &k)
{
while(x!=k)
{
int y=fa[x],z=fa[y];
if(y!=k)
{
if((c[y][]==x)^(c[z][]==y)) rotate(x,k);
else rotate(y,k);
}
rotate(x,k);
}
}
void build(int k,int l,int r)
{
if(l>r) return;
if(l==r)
{
v[l]=h[l]=ch[l]-'a'+;
fa[l]=k; size[l]=;
if(l<k) c[k][]=l;
else c[k][]=l;
return;
}
int mid=(l+r)/;
build(mid,l,mid-); build(mid,mid+,r);
v[mid]=ch[mid]-'a'+; fa[mid]=k; updata(mid);
if(mid<k) c[k][]=mid;
else c[k][]=mid;
}
int find(int k,int rank)
{
int l=c[k][],r=c[k][];
if(size[l]+==rank) return k;
else if(size[l]>=rank) return find(l,rank);
else return find(r,rank-size[l]-);
}
int check(int k,int val)
{
int x=find(rt,k),y=find(rt,k+val+);
Splay(x,rt); Splay(y,c[x][]);
int z=c[y][];
return h[z];
}
int ask(int x,int y)
{
int l=,r=min(sz-x,sz-y)-,ans=;
while(l<=r)
{
int mid=(l+r)/;
if(check(x,mid)==check(y,mid)) {l=mid+; ans=mid;}
else r=mid-;
}
return ans;
}
void insert(int k,int val)
{
int x=find(rt,k+),y=find(rt,k+);
Splay(x,rt); Splay(y,c[x][]);
int z=++sz; c[y][]=z; fa[z]=y; v[z]=val;
updata(z); updata(y); updata(x);
}
}using namespace SPLAY;
int main()
{
//freopen("cin.in","r",stdin);
//freopen("cout.out","w",stdout);
scanf("%s",ch+);
n=strlen(ch+); p[]=;
for(int i=;i<=MAXN;i++) p[i]=p[i-]*%mod;
build(,,n+); rt=(n+)/; sz=n+;
m=read(); int x,y;
char s[],d[];
for(int i=;i<=m;i++)
{
scanf("%s",s+); x=read();
if(s[]=='Q') {y=read(); printf("%d\n",ask(x,y));}
if(s[]=='R') {scanf("%s",d+); x=find(rt,x+); Splay(x,rt); v[rt]=d[]-'a'+; updata(rt);}
if(s[]=='I') {scanf("%s",d+); insert(x,d[]-'a'+);}
}
return ;
}
附makedata程序(博主很良心,知道你会wa):
#include<iostream>
using namespace std;
char ch[]={'Q','R','I'};
int main()
{
freopen("cin.in","w",stdout);
srand(time(NULL));
int n=;
for(int i=;i<=n;i++) printf("%c",(char)('a'+rand()%));
printf("\n");
int m=;
printf("%d\n",m);
for(int i=;i<=m;i++)
{
char f=ch[rand()%];
if(f=='Q') {printf("%c %d %d\n",f,rand()%n+,rand()%n+);}
if(f=='R') {printf("%c %d %c\n",f,rand()%n+,(char)('a'+rand()%));}
if(f=='I') {printf("%c %d %c\n",f,rand()%n+,(char)('a'+rand()%));}
}
return ;
}
【bzoj1014】[JSOI2008]火星人prefix的更多相关文章
- [BZOJ1014][JSOI2008]火星人prefix
[BZOJ1014][JSOI2008]火星人prefix 试题描述 火星人最近研究了一种操作:求一个字串两个后缀的公共前缀.比方说,有这样一个字符串:madamimadam,我们将这个字符串的各个字 ...
- BZOJ1014 JSOI2008 火星人prefix 【非旋转Treap】*
BZOJ1014 JSOI2008 火星人prefix Description 火星人最近研究了一种操作:求一个字串两个后缀的公共前缀.比方说,有这样一个字符串:madamimadam,我们将这个字符 ...
- 2018.06.28 BZOJ1014 [JSOI2008]火星人prefix(非旋treap+hash)
[JSOI2008]火星人prefix Time Limit: 10 Sec Memory Limit: 162 MB Submit: 8951 Solved: 2860 Description 火星 ...
- bzoj千题计划106:bzoj1014 [JSOI2008]火星人prefix
http://www.lydsy.com/JudgeOnline/problem.php?id=1014 两个后缀的最长公共前缀:二分+hash 带修改带插入:splay维护 #include< ...
- [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 ...
- [bzoj1014](JSOI2008)火星人 prefix (Splay维护哈希)
Description 火星人最近研究了一种操作:求一个字串两个后缀的公共前缀. 比方说,有这样一个字符串:madamimadam,我们将这个字符串的各个字符予以标号:序号: 1 2 3 4 5 6 ...
- BZOJ1014[JSOI2008]火星人prefix(splay维护hash)
Description 火星人最近研究了一种操作:求一个字串两个后缀的公共前缀.比方说,有这样一个字符串:madamimadam,我们将这个字符串的各个字符予以标号:序号: 1 2 3 4 5 6 7 ...
- BZOJ1014: [JSOI2008]火星人prefix(splay 二分 hash)
题意 题目链接 Sol 一眼splay + 二分hash,不过区间splay怎么写来着呀 试着写了两个小时发现死活不对 看了一下yyb的代码发现自己根本就不会splay.... // luogu-ju ...
- bzoj1014: [JSOI2008]火星人prefix(splay+hash+二分)
题目大意:一个字符串三个操作:①求两个后缀的LCP②插入一个字符③修改一个字符. 前几天刚学了hash+二分求lcp,就看到这题. 原来splay还能这么用?!原来splay模板这么好写?我以前写的s ...
随机推荐
- MongoDB(4):多种方式关闭服务命令
http://blog.csdn.net/czw698/article/details/8791153 MongoDB 提供几种关闭服务的命令,具体为以下: 一 使用 Crtl+C 关闭 [mong ...
- 集群session的一致性
一. 何为session 用户使用网站的服务,基本上需要浏览器和web服务器进行多次交互,web服务器如何知道哪些请求是来自哪个会话的? 具体方式为:在会话开始时,分配一个唯一的会话标识(sessio ...
- 【Weblogic】--Weblogic的部署方式和缓存
参考网址: http://dead-knight.iteye.com/blog/1938882 Weblogic11g部署web应用,有三种方式,非常简单,但是很多新手部署总是出现若干错误,不知道如何 ...
- 问题记录-Fragment导包不同导致无法自动转型
代码如下 public class MainActivity extends FragmentActivity { @Override public void onCreate(Bundle save ...
- iPhone开发中的技巧整理
1.NSCalendar用法 -(NSString *) getWeek:(NSDate *)d { NSCalendar *calendar = [[NSCalendar alloc] initWi ...
- Nginx服务器架构简析
一.Nginx的模块化 模块化结构的思想是一个很久的概念,但也正是成熟的思想造就了Nginx的巨大优越性. 我们知道Nginx从总体上来讲是有许多个模块构成的.习惯将Nginx分为5大模块分别为:核心 ...
- 九度oj 1407 快速找出最小数
原题链接:http://ac.jobdu.com/problem.php?pid=1407 线段树,区间更新,查询区间最小值. 注意区间更新,查询的时候,区间$\begin{align*}[L,R] ...
- 【转】Git常用命令备忘
Git配置 git config --global user.name "robbin" git config --global user.email "fankai@g ...
- ifstat-网络接口监测工具
ifstat-网络接口监测工具 http://gael.roualland.free.fr/ifstat/ ifstat is a tool to report network interfaces ...
- iOS 进阶 第十八天(0423)
0423 - GCD( Grand Central Dispatch) block复习 请问,图中输出结果是多少?为什么? 答:结果是10.因为在定义block的时候,block会把它前面的要用到的变 ...