bzoj 1014 火星人prefix —— splay+hash
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1014
用 splay 维护字符串上不同位置的哈希值还是第一次...
具体就是每个节点作为位置被不断旋转,点上维护的哈希值就是此时它及其儿子这一段区间的哈希值;
要查询 LCQ,可以二分一个长度,然后把两端区间分别旋转到根,取出哈希值比较;
据说用模数会很慢,写自然溢出比较好;
因为忘记 rotate 最后要 pushup 而调了很久...注释里是另一种可以A的 rotate - splay 系列;
又加深了对 splay 的理解,它的节点表示位置关系...
代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define mid ((l+r)>>1)
using namespace std;
typedef unsigned long long ll;
int const xn=1e5+,xm=;
int n,m,rt,fa[xm],c[xm][],siz[xm];
ll pw[xm],hsh[xm];
char s[xn],ch[xn];
void pushup(int x)
{
int ls=c[x][],rs=c[x][];
siz[x]=siz[ls]+siz[rs]+;
hsh[x]=hsh[ls]*pw[siz[rs]+]+(s[x]-'a'+)*pw[siz[rs]]+hsh[rs];
}
void rotate(int x,int &f)
{
int y=fa[x],z=fa[y],d=(c[y][]==x);
if(z)c[z][c[z][]==y]=x;
// if(y==f)f=x; else c[z][c[z][1]==y]=x;
fa[x]=z; fa[y]=x; fa[c[x][!d]]=y;
c[y][d]=c[x][!d]; c[x][!d]=y;
pushup(y); pushup(x);//!!!
}
void splay(int x,int f)//
{
while(fa[x]!=f)//
{
int y=fa[x],z=fa[y];
if(z!=f)//
{
if((c[y][]==x)^(c[z][]==y))rotate(x,f);
else rotate(y,f);
}
rotate(x,f);
}
if(!f)rt=x;
}
void build(int l,int r,int lst)
{
if(l>r)return;
if(l==r)hsh[l]=s[l]-'a'+,siz[l]=;
else build(l,mid-,mid),build(mid+,r,mid);
fa[mid]=lst; c[lst][mid>lst]=mid; pushup(mid);
}
int find(int x,int k)//找到 k 位置
{
while()
{
int p=c[x][],q=c[x][];
if(siz[p]+==k)return x;
else if(siz[p]+<k)x=q,k-=siz[p]+;
else x=p;
}
}
void insert(int pos,char d)
{
s[++n]=d; hsh[n]=d-'a'+;
int x=find(rt,pos+);//+1 因为有左右的'a'
splay(x,); x=find(rt,pos+); splay(x,rt);//
// splay(x,rt); x=find(rt,pos+2); splay(x,c[rt][1]);
c[x][]=n; siz[n]=; fa[n]=x;
pushup(x); pushup(rt);
}
void change(int pos,char d)
{
int x=find(rt,pos+);
splay(x,);//
// splay(x,rt);
s[x]=d; pushup(x);
}
bool ck(int l,int r,int k)
{
ll h1=,h2=;
// int x=find(rt,l); splay(x,rt);//
// x=find(rt,l+k+1); splay(x,c[rt][1]);
// x=c[rt][1];//
int x=find(rt,l); splay(x,);
x=find(rt,l+k+); splay(x,rt);
h1=hsh[c[x][]];
// x=find(rt,r); splay(x,rt);//
// x=find(rt,r+k+1); splay(x,c[rt][1]);
// x=c[rt][1];//
x=find(rt,r); splay(x,);
x=find(rt,r+k+); splay(x,rt);
h2=hsh[c[x][]];
return h1==h2;
}
int query(int x,int l,int r)
{
int ll=,rr=n--max(l,r)+,ret=;
while(ll<=rr)
{
int md=((ll+rr)>>);
if(ck(l,r,md))ret=md,ll=md+;
else rr=md-;
}
return ret;
}
void init()
{
n=strlen(s+); pw[]=;
for(int i=;i<=xm-;i++)pw[i]=pw[i-]*;
s[]=s[n+]='a';
build(,n+,); n=n+; rt=(n+)/;//
}
int main()
{
scanf("%s",s+); init();
scanf("%d",&m);
for(int i=,x,y;i<=m;i++)
{
scanf("%s%d",ch,&x);
if(ch[]=='I')scanf("%s",ch),insert(x,ch[]);
if(ch[]=='R')scanf("%s",ch),change(x,ch[]);
if(ch[]=='Q')scanf("%d",&y),printf("%d\n",query(rt,x,y));
}
return ;
}
bzoj 1014 火星人prefix —— splay+hash的更多相关文章
- BZOJ 1014: [JSOI2008]火星人prefix( splay + hash )
用splay维护序列, 二分+hash来判断LCQ.. #include<bits/stdc++.h> using namespace std; typedef unsigned long ...
- BZOJ 1014 [JSOI2008]火星人prefix (Splay + Hash + 二分)
1014: [JSOI2008]火星人prefix Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 8112 Solved: 2569[Submit] ...
- 【BZOJ1014】[JSOI2008]火星人prefix Splay+hash
[BZOJ1014][JSOI2008]火星人prefix Description 火星人最近研究了一种操作:求一个字串两个后缀的公共前缀.比方说,有这样一个字符串:madamimadam,我们将这个 ...
- 【bzoj1014】[JSOI2008]火星人prefix Splay+Hash+二分
题目描述 火星人最近研究了一种操作:求一个字串两个后缀的公共前缀.比方说,有这样一个字符串:madamimadam,我们将这个字符串的各个字符予以标号:序号: 1 2 3 4 5 6 7 8 9 10 ...
- $bzoj1014-JSOI2008$ 火星人$prefix$ $splay$ $hash$
题面描述 火星人最近研究了一种操作:求一个字串两个后缀的公共前缀.比方说,有这样一个字符串:\(madamimadam\),我们将这个字符串的各个字符予以标号: 序号 1 2 3 4 5 6 7 8 ...
- 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 - 链表 - 分块
Description 火星人最近研究了一种操作:求一个字串两个后缀的公共前缀.比方说,有这样一个字符串:madamimadam,我们将这个字符串的各个字符予以标号:序号: 1 2 3 4 5 6 7 ...
- bzoj1014: [JSOI2008]火星人prefix splay+hash+二分
Description 火星人最近研究了一种操作:求一个字串两个后缀的公共前缀.比方说,有这样一个字符串:madamimadam,我们将这个字符串的各个字符予以标号:序号: 1 2 3 4 5 6 7 ...
随机推荐
- [vijos1159]岳麓山上打水
[vijos1159]岳麓山上打水 试题描述 今天天气好晴朗,处处好风光,好风光!蝴蝶儿忙啊,蜜蜂也忙,信息组的同学们更加忙.最近,由于XX原因,大家不得不到岳麓山去提水.55555555~,好累啊. ...
- HDU 2255 二分图最佳匹配
奔小康赚大钱 Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Subm ...
- Substrings--poj1226(字符串)
Description You are given a number of case-sensitive strings of alphabetic characters, find the larg ...
- MySQL中的数据类型的长度范围和显示宽度(转)
长度范围是随数据类型就已经是固定的值,而显示宽度与长度范围无关. 以下是每个整数类型的存储和范围(来自MySQL手册) 类型 字节 最小值 最大值 (带符号的/无符号的) (带符号的/无符号的) TI ...
- Javascript小数取整方法收集
1.丢弃小数部分,保留整数部分 parseInt(7/2) 2.向上取整,有小数就整数部分加1 Math.ceil(7/2) 3.四舍五入 Math.round(7/2) 4.向下取整 Math.fl ...
- 搜索引擎keyword智能提示的一种实现
问题背景 搜索关键字智能提示是一个搜索应用的标配.主要作用是避免用户输入错误的搜索词,并将用户引导到相应的关键词上,以提升用户搜索体验. 美团CRM系统中存在数以百万计的商家,为了让用户高速查找到目标 ...
- HTML的DIV如何实现水平居中
内部的DIV必须有下面两行代码即可 text-align:center; margin:0 auto; 在IE6中同样可以
- AFNetworking配合Swift3.0请求数据
首先用桥接或pods将AFNetworking导入项目,在这不再赘述,然后创建一个单例NetWorkTools.swift 继承:AFHTTPSessionManager import UIKit i ...
- HDU 1176-免费馅饼(DP_逆推)
免费馅饼 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Submi ...
- 《Java设计模式》之訪问者模式
訪问者模式是对象的行为模式.訪问者模式的目的是封装一些施加于某种数据结构元素之上的操作.一旦这些操作须要改动的话,接受这个操作的数据结构则能够保持不变. 分派的概念 变量被声明时的类型叫做变量的静态类 ...