题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1014

用splay维护字符串,每个点记录子树的哈希值,然后二分查询。

二分不是把两个点的哈希值拿出来二分!因为取模了所以不能还原;因为splay维护了字符串,所以二分答案后把对应一段转出来看看哈希值一不一样就行了。

如果一开始不是用给出的序列直接建一个树(就是递归 l,mid-1 和 mid+1,r 那样的),而是像我一开始一样一个一个往进插入的话,不知为何过不了呢。

有些卡时间。据说%mod会T,于是用 unsigned long long 自然溢出。

用 nxt 找后继的时候要先把对象旋转到根才行。

幂也要预处理以防超时。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#define ll unsigned long long
using namespace std;
const int N=2e5+,base=;
int n,tot,c[N][],fa[N],rt,siz[N];
ll val[N],sm[N],pw[N];
char ch[N];
int init()
{
pw[]=;
for(int i=;i<=N-;i++) pw[i]=pw[i-]*base;
}
void pshp(int cr)
{
int ls=c[cr][],rs=c[cr][];
siz[cr]=siz[ls]+siz[rs]+; val[cr]=(val[rs]*base+sm[cr])*pw[siz[ls]]+val[ls];
}
void rotate(int x,int &k)
{
int y=fa[x],z=fa[y];
if(y==k) k=x;
else c[z][y==c[z][]]=x;
int d=(x==c[y][]);
fa[x]=z; fa[y]=x; fa[c[x][!d]]=y;
c[y][d]=c[x][!d]; c[x][!d]=y;
pshp(y); pshp(x);
}
void splay(int x,int &k)
{
while(x!=k)
{
int y=fa[x],z=fa[y];
if(y!=k)
{
if((x==c[y][])^(y==c[z][]))
rotate(x,k);
else rotate(y,k);
}
rotate(x,k);
}
}
int find(int p)
{
int cr=rt;
while(cr)
{
if(siz[c[cr][]]+==p)return cr;
else if(siz[c[cr][]]+<p)
{
p-=siz[c[cr][]]+;
cr=c[cr][];
}
else cr=c[cr][];
}
}
int nxt(int cr)
{
cr=c[cr][];
while(c[cr][]) cr=c[cr][];
return cr;
}
void insert(int p,int v)
{
int d=find(p); splay(d,rt);
int x=nxt(d); splay(x,c[rt][]);
siz[++tot]=; val[tot]=sm[tot]=v;
fa[tot]=x; c[x][]=tot;
pshp(x); pshp(d);
}
void mdfy(int p,int v)
{
int d=find(p); splay(d,rt);
sm[d]=v; pshp(d);
}
ll cz(int u,int v)
{
splay(u,rt);
int k=find(v);
splay(k,c[rt][]);
return val[c[k][]];
}
void query(int u,int v)
{
int l=,r=min(tot-u,tot-v);
int ans=;
int x=find(u-), y=find(v-);
while(l<=r)
{
int mid=l+r>>;
if(cz(x,u+mid)==cz(y,v+mid)) ans=mid,l=mid+;
else r=mid-;
}
printf("%d\n",ans);
}
void build(int l,int r,int lst,bool fx)
{
if(l>r) return;
int mid=l+r>>;
int cr=++tot; fa[cr]=lst; c[lst][fx]=cr;
sm[cr]=ch[mid]-'a'+;
if(l==r) {val[cr]=sm[cr]; siz[cr]=; return;}
build(l,mid-,cr,); build(mid+,r,cr,);
pshp(cr);
}
int main()
{
init();
scanf("%s",ch+); n=strlen(ch+);
ch[]='a'; ch[n+]='a'; n+=;
build(,n,,); rt=; c[][]=;
scanf("%d",&n);
for(int i=,x,d;i<=n;i++)
{
cin>>ch[];
if(ch[]=='I')
{
scanf("%d %c",&x,&ch[]);
d=ch[]-'a'+; insert(x+,d);
}
if(ch[]=='R')
{
scanf("%d %c",&x,&ch[]);
d=ch[]-'a'+; mdfy(x+,d);
}
if(ch[]=='Q')
{
scanf("%d%d",&x,&d);
query(x+,d+);
}
}
return ;
}

bzoj 1014 [JSOI2008]火星人prefix——splay+哈希的更多相关文章

  1. BZOJ 1014: [JSOI2008]火星人prefix [splay 二分+hash] 【未完】

    1014: [JSOI2008]火星人prefix Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 6243  Solved: 2007[Submit] ...

  2. BZOJ 1014: [JSOI2008]火星人prefix Splay+二分

    1014: [JSOI2008]火星人prefix 题目连接: http://www.lydsy.com/JudgeOnline/problem.php?id=1014 Description 火星人 ...

  3. BZOJ 1014: [JSOI2008]火星人prefix( splay + hash )

    用splay维护序列, 二分+hash来判断LCQ.. #include<bits/stdc++.h> using namespace std; typedef unsigned long ...

  4. BZOJ 1014 [JSOI2008]火星人prefix (Splay + Hash + 二分)

    1014: [JSOI2008]火星人prefix Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 8112  Solved: 2569[Submit] ...

  5. BZOJ 1014 [JSOI2008]火星人prefix | Splay维护哈希值

    题目: 题解: #include<cstdio> #include<algorithm> #include<cstring> typedef long long l ...

  6. BZOJ 1014 [JSOI2008]火星人prefix (splay+二分答案+字符串hash)

    题目大意:维护一个字符串,支持插入字符和替换字符的操作,以及查询该字符串两个后缀的最长公共前缀长度 乍一看以为是后缀数组,然而并没有可持久化后缀数组(雾) 看题解才知道这是一道splay题,首先要对s ...

  7. bzoj 1014: [JSOI2008]火星人prefix hash && splay

    1014: [JSOI2008]火星人prefix Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 3154  Solved: 948[Submit][ ...

  8. 求帮看!!!!BZOJ 1014 [JSOI2008]火星人prefix

    1014: [JSOI2008]火星人prefix Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 4164  Solved: 1277[Submit] ...

  9. [BZOJ 1014] [JSOI2008] 火星人prefix 【Splay + Hash】

    题目链接:BZOJ - 1014 题目分析 求两个串的 LCP ,一种常见的方法就是 二分+Hash,对于一个二分的长度 l,如果两个串的长度为 l 的前缀的Hash相等,就认为他们相等. 这里有修改 ...

随机推荐

  1. [Algorithms] Queue & Priority Queue

    In this lesson, you will learn how to create a queue in JavaScript. A queue is a first-in, first-out ...

  2. 关于C++ 命名空间Namespace 的解析

    使用命名空间的目的是对标识符的名称进行本地化,以避免命名冲突.在C++中,变量.函数和类都是大量存在的.如果没有命名空间,这些变量.函数.类的名称将都存在于全局命名空间中,会导致很多冲突.比如,如果我 ...

  3. ListView中button监听器 设置 及 优化

    在应用开发中常常会用到ListView,而且每个Item里面都会有button之类的须要进行事件监听的控件.在给button加入OnClickListener的时候,一開始非常下意识的会想在ListV ...

  4. Docker在centos下安装以及常见错误解决

    系列目录 Docker安装(使用阿里云镜像) Docker从1.13版本之后采用时间线的方式作为版本号,分为社区版CE和企业版EE. 社区版是免费提供给个人开发者和小型团体使用的,企业版会提供额外的收 ...

  5. MySQL 创始人:写代码比打游戏爽,程序员应多泡开源社区

     王练 发布于2017年09月04日 收藏 43   开源中国全球专享福利,云栖大会购票大返现!>>>   根据StackOverflow的最新调查,MySQL仍然是全世界最流行的数 ...

  6. LeetCode:判断最长前缀

    之前一直忽略了一个问题就是:给定的空字符串数组 char* longestCommonPrefix(char** strs, int strsSize) { char* result; if(strs ...

  7. Riak Core Guide 2

    Learn Riak Core Step By Step 2 Riak Core, The Coordinator What is a Coordinator? 顾名思义. Coordinator即使 ...

  8. Linux常用命令——持续更新(2018-05-09)

    此命令默认是在centos环境下执行,除非特殊标明. 1.查看ip: ifconfig 2.创建指定用户并分配到某个组:创建用户user并分配到root组 useradd -g root user 3 ...

  9. Git检出远程库的分支等相关操作

    来到公司,询问同事后发现系统已经上传到Git远程仓库: 我这里先把远程仓库clone下来: $ git clone http://git.eas****tect.git 发现目录下只有一个READY. ...

  10. Tomcat之catalina.out日志分割

    可参考:http://meiling.blog.51cto.com/6220221/1911769 本人尚未验证.