【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 ...
随机推荐
- varnish状态引擎2
如何让varnish支持虚拟主机: if (req.http.host = "www.nihao.com") { } 强制对某资源的请求,不检查缓存: 上图表示以/test1.ht ...
- Spark自定义分区(Partitioner)
我们都知道Spark内部提供了HashPartitioner和RangePartitioner两种分区策略,这两种分区策略在很多情况下都适合我们的场景.但是有些情况下,Spark内部不能符合咱们的需求 ...
- 什么是Ajax无刷新技术?
浏览器实例化一个Ajax对象,这个对象发送一个HTTP请求,并且携带一定的参数,传输到后台.后台服务器接收这些参数,同时过滤一下传过来的参数,做出逻辑判断.如果需要数据库操作参与,就要取出数据,格式化 ...
- 入门级的PHP验证码
参考了网上PHP 生成验证码很多是类封装了的,没有封装的验证码其实只是几个GD函数而已,初学者可以看看,可以尝试自己封装. <?php session_start(); $im = ...
- 西门子SIMATIC IT平台
西门子公司的SIMATIC IT平台基于ANSI/ISA S95标准开发,包含的功能组件覆盖了ISA S95规定的生产业务操作模型,同时也满足MESA所确定的MES系统11项功能要求. SIMATIC ...
- Ruby实现wordCounter
做解密发现的: m={} File.open("test1.txt") do |f| f.each_line do |line| line.chomp! #去除每行结尾的回车(\n ...
- DB2中ixf文件的导入导出
1. 导出数据 语法:EXPORT TO <文件路径>/文件名.IXF OF IXF SELECT * FROM 表名 2. 导入数据 语法:db2 IMPORT FROM <路 ...
- CSV 文件读取类
class CsvReader { private $csv_file; private $spl_object = null; private $error; public function __c ...
- Convert Geometry data into a Geography data in MS SQL Server
DECLARE @geog GEOGRAPHY; DECLARE @geom GEOMETRY; ); SET @geom = @geom.MakeValid() --Force to valid g ...
- C#操作FTP, FTPHelper和SFTPHelper
1. FTPHelper using System; using System.Collections.Generic; using System.IO; using System.Net; usin ...