BZOJ 1014 [JSOI2008]火星人prefix (splay+二分答案+字符串hash)
题目大意:维护一个字符串,支持插入字符和替换字符的操作,以及查询该字符串两个后缀的最长公共前缀长度
乍一看以为是后缀数组,然而并没有可持久化后缀数组(雾)
看题解才知道这是一道splay题,首先要对splay维护区间信息有一定了解
splay维护,插入字符,替换字符
而它的字树内所有儿子的中序遍历的hash值也可以通过splay维护
(这个推导式似乎烂大街了)
而后缀就是把i-1拎到根节点,然后把n+1拎到根节点的右儿子上,它的左儿子表示的就是hash值
至于如何查公共前缀呢?二分答案啊!询问的总时间是
这个二分答案的check函数 的满足条件并非常规的>=或者<=,而是==,所以为了防止正确答案被略掉,每次二分的过程中都记录一次mid作为答案,而加下来mid在查询范围内已经没有意义了,所以是r=mid-1而不是r=mid
我一开始插入打错了竟然还有80分,数据太水了hhhhh
#include <cstdio>
#include <cstring>
#include <algorithm>
#define il inline
#define ui unsigned int
#define ull unsigned long long
#define seed 13131
#define N 110000
#define root d[0].ch[1]
using namespace std; char str[N],Q[],q[];
ull pw[N];
int n,m,tot;
struct SPLAY{int fa,ch[],sz;ull hsh,val;}d[N];
int gc()
{
int rett=,fh=;char p=getchar();
while(p<''||p>''){if(p=='-')fh=-;p=getchar();}
while(p>=''&&p<=''){rett=(rett<<)+(rett<<)+p-'';p=getchar();}
return rett*fh;
}
il ull idx(char c){return c-'a'+;}
il void con(int x,int ff,int p){d[x].fa=ff,d[ff].ch[p]=x;}
il int idf(int x){return d[d[x].fa].ch[]==x?:;}
il int cre(ull w){tot++;d[tot].val=w,d[tot].sz=,d[tot].hsh=w;return tot;}
il void pushup(int x)
{
d[x].sz=d[d[x].ch[]].sz+d[d[x].ch[]].sz+;
d[x].hsh=d[d[x].ch[]].hsh*pw[d[d[x].ch[]].sz+]+(ull)d[x].val*pw[d[d[x].ch[]].sz]+d[d[x].ch[]].hsh;
}
il void rot(int x)
{
int y=d[x].fa;int ff=d[y].fa;int px=idf(x);int py=idf(y);
con(d[x].ch[px^],y,px),con(y,x,px^),con(x,ff,py);
pushup(y),pushup(x);
}
void splay(int x,int to)
{
to=d[to].fa;
while(d[x].fa!=to){
int y=d[x].fa;
if(d[y].fa==to) rot(x);
else if(idf(x)==idf(y)){rot(y);rot(x);}
else{rot(x);rot(x);}
}
}
int build(int l,int r,int ff)
{
if(l>r) return ;
int mid=(l+r)>>;
int pos=cre(idx(str[mid]));
d[pos].fa=ff;
d[pos].ch[]=build(l,mid-,pos);
d[pos].ch[]=build(mid+,r,pos);
pushup(pos);
return pos;
}
int find_pos(int pos)
{
int x=root;
while(x)
{
if(d[d[x].ch[]].sz>=pos) x=d[x].ch[];
else{
pos-=d[d[x].ch[]].sz;
if(pos==) return x;
pos--,x=d[x].ch[];
}
}
return x;
}
void ins(int pos,ull w)
{
int ff=find_pos(pos+),x,y;splay(ff,root);
if(!d[ff].ch[])
x=cre(w),con(x,ff,),pushup(ff);
else{
x=d[ff].ch[];
while(x)
if(d[x].ch[]) x=d[x].ch[];
else break;
y=cre(w),con(y,x,),pushup(x);
splay(x,root);
}
}
void replac(int pos,ull w)
{
int x=find_pos(pos+);splay(x,root);
d[x].val=w;pushup(x);
}
il ull get_hsh(int pos)
{
int x=find_pos(pos);
splay(x,root);
int y=find_pos(n+);
splay(y,d[x].ch[]);
return d[d[d[x].ch[]].ch[]].hsh;
}
il int check(int x,int y,int mid)
{
ull s1=,s2=,s3=,s4=;
s1=get_hsh(x);
if(x+mid<=n) s2=get_hsh(x+mid);
s3=get_hsh(y);
if(y+mid<=n) s4=get_hsh(y+mid);
return (s1-s2==(s3-s4)*pw[y-x])?:;
}
int Query(int a,int b)
{
if(a>b){int t=a;a=b;b=t;}
int l=,r=n-b+,ans=;
while(l<=r){
int mid=(l+r)>>;
if(check(a,b,mid)) ans=mid,l=mid+;
else r=mid-;
}
return ans;
}
void stt()
{
n=strlen(str+);pw[]=;
for(int i=;i<=;i++) pw[i]=pw[i-]*seed;
int x=cre(),y=cre(),z;
con(x,,),con(y,,);
z=build(,n,y);
con(z,y,);
pushup(y),pushup(x);
} int main()
{
scanf("%s",str+);
stt();
scanf("%d",&m);
int x,y;
for(int i=;i<=m;i++)
{
scanf("%s",Q);
if(Q[]=='Q'){
x=gc(),y=gc();
printf("%d\n",Query(x,y));
}else if(Q[]=='I'){
x=gc();scanf("%s",q);
ins(x,idx(q[]));
n++;
}else{
x=gc();scanf("%s",q);
replac(x,idx(q[]));
}
}
return ;
}
BZOJ 1014 [JSOI2008]火星人prefix (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 (Splay + Hash + 二分)
1014: [JSOI2008]火星人prefix Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 8112 Solved: 2569[Submit] ...
- BZOJ 1014: [JSOI2008]火星人prefix( splay + hash )
用splay维护序列, 二分+hash来判断LCQ.. #include<bits/stdc++.h> using namespace std; typedef unsigned long ...
- [BZOJ1014] [JSOI2008] 火星人prefix (splay & 二分答案)
Description 火星人最近研究了一种操作:求一个字串两个后缀的公共前缀.比方说,有这样一个字符串:madamimadam,我们将这个字符串的各个字符予以标号:序号: 1 2 3 4 5 6 7 ...
- bzoj 1014 [JSOI2008]火星人prefix——splay+哈希
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1014 用splay维护字符串,每个点记录子树的哈希值,然后二分查询. 二分不是把两个点的哈希 ...
- BZOJ 1014 [JSOI2008]火星人prefix | Splay维护哈希值
题目: 题解: #include<cstdio> #include<algorithm> #include<cstring> typedef long long l ...
- 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] ...
随机推荐
- [bzoj3505 Cqoi2014] 数三角形 (容斥+数学)
传送门 Description 给定一个nxm的网格,请计算三点都在格点上的三角形共有多少个.下图为4x4的网格上的一个三角形. 注意三角形的三点不能共线. Input 输入一行,包含两个空格分隔的正 ...
- [洛谷 P1967] 货车运输 (最大生成树 lca)
题目描述 A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路.每一条道路对车辆都有重量限制,简称限重.现在有 q 辆货车在运输货物, 司机们想知道每辆车在不超过车辆限重的情况下,最多 ...
- 搞定PHP面试 - 变量知识点整理
一.变量的定义 1. 变量的命名规则 变量名可以包含字母.数字.下划线,不能以数字开头. $Var_1 = 'foo'; // 合法 $var1 = 'foo'; // 合法 $_var1 = 'fo ...
- struts配置问题
- 用友ERP T6技术解析(六) 库龄分析
2.4 库存管理 2.4.1 库龄分析 介绍:库存账龄是在某时间节点,某种或某类存货的库存时间的加权平均值,跟库存周转率关系明显,库存周转率越高,库存账龄越低,可是二者又不是反比关系.不能简单把库 ...
- UVA 10196 Morning Walk(欧拉回路)
Problem H Morning Walk Time Limit 3 Seconds Kamalis a Motashotaguy. He has got a new job in Chittago ...
- 使用Service Bus Topic 实现简单的聊天室
创建Service Bus能够參照: https://azure.microsoft.com/en-gb/documentation/articles/service-bus-dotnet-how-t ...
- Quartz2D二维画图引擎
Quartz2D二维画图引擎 这个二维画图引擎的功能很强大 一般苹果公司xcode 提供给我们的一些UI控件不能满足我们的需求 所以我们会自己定义控件 xcode 提供的全部控件都是由这个画图引擎画出 ...
- 公布项目到NPM
修己安人,内圣外王 近期,在开发Node项目过程中遇到了须要类jQuery深拷贝对象的问题.去Github找了半天,并没有符合的,于是,自己决定写一个(mixin.js),然后推送到NPM(查看Npm ...
- 谷歌开源可视化工具Facets,将用于人+AI协作项目研究——无非就是一个用于特征工程探索的绘图工具集,pandas可以做的
见:http://www.infoq.com/cn/news/2017/07/goole-sight-facets-ai https://github.com/PAIR-code/facets/blo ...