题目: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的更多相关文章

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

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

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

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

  3. 【BZOJ1014】[JSOI2008]火星人prefix Splay+hash

    [BZOJ1014][JSOI2008]火星人prefix Description 火星人最近研究了一种操作:求一个字串两个后缀的公共前缀.比方说,有这样一个字符串:madamimadam,我们将这个 ...

  4. 【bzoj1014】[JSOI2008]火星人prefix Splay+Hash+二分

    题目描述 火星人最近研究了一种操作:求一个字串两个后缀的公共前缀.比方说,有这样一个字符串:madamimadam,我们将这个字符串的各个字符予以标号:序号: 1 2 3 4 5 6 7 8 9 10 ...

  5. $bzoj1014-JSOI2008$ 火星人$prefix$ $splay$ $hash$

    题面描述 火星人最近研究了一种操作:求一个字串两个后缀的公共前缀.比方说,有这样一个字符串:\(madamimadam\),我们将这个字符串的各个字符予以标号: 序号 1 2 3 4 5 6 7 8 ...

  6. BZOJ 1014 火星人prefix

    Description 火星人最近研究了一种操作:求一个字串两个后缀的公共前缀.比方说,有这样一个字符串:madamimadam,我们将这个字符串的各个字符予以标号:序号: 1 2 3 4 5 6 7 ...

  7. [BZOJ]1014 火星人prefix(JSOI2008)

    一边听省队dalao讲课一边做题真TM刺激. BZOJ的discuss简直就是题面plus.大样例.SuperHINT.dalao题解的结合体. Description 火星人最近研究了一种操作:求一 ...

  8. bzoj 1014 火星人prefix - 链表 - 分块

    Description 火星人最近研究了一种操作:求一个字串两个后缀的公共前缀.比方说,有这样一个字符串:madamimadam,我们将这个字符串的各个字符予以标号:序号: 1 2 3 4 5 6 7 ...

  9. bzoj1014: [JSOI2008]火星人prefix splay+hash+二分

    Description 火星人最近研究了一种操作:求一个字串两个后缀的公共前缀.比方说,有这样一个字符串:madamimadam,我们将这个字符串的各个字符予以标号:序号: 1 2 3 4 5 6 7 ...

随机推荐

  1. git修改commit message及vi编辑器的简单使用

    1.修改commit信息 git commit --amend 2.进入vi编辑器修改 ‘i’进入insert模式,输入文字: ‘esc’回到命令模式,删除文字,移动光标: ‘:’进入底行模式,‘wq ...

  2. 洛谷—— P2802 回家

    P2802 回家 题目描述 小H在一个划分成了n*m个方格的长方形封锁线上. 每次他能向上下左右四个方向移动一格(当然小H不可以静止不动), 但不能离开封锁线,否则就被打死了. 刚开始时他有满血6点, ...

  3. 洛谷—— P1656 炸铁路

    P1656 炸铁路 题目描述 因为某国被某红色政权残酷的高压暴力统治.美国派出将军uim,对该国进行战略性措施,以解救涂炭的生灵. 该国有n个城市,这些城市以铁路相连.任意两个城市都可以通过铁路直接或 ...

  4. POJ 1511 【heap+dij】

    题意: t组样例. 每组有n个节点,有m条单向边. 有m组输入,每组a b c 表示从a到b的单向边的权值是c. 求解,从编号为1的节点出发,有n-1个人,要求他们分别到达编号从2到n的节点再返回,所 ...

  5. Atom安装代码格式化插件atom-beautify

    官网:https://github.com/Glavin001/atom-beautify 效果: 使用: [cmd]-[shift]-[p]或者[ctrl]-[shift]-[p]

  6. 解决WIN7下VMWARE虚拟机无法上网问题

    一.Win7 虚拟机centos NAT联网 链接地址:http://www.cr173.com/html/19808_1.html,也不知道是哪位大神弄的,实践过,可以使用,但是重启之后却不能用了, ...

  7. linux的bc命令介绍

    bc命令是一种支持任意精度的交互执行的计算器语言.bash内置了对整数四则运算的支持,但是并不支持浮点运算,而bc命令可以很方便的进行浮点运算,当然整数运算也不再话下. 算术操作高级运算bc命令它可以 ...

  8. linux定时重启节约内存

    linux服务器上运行的一些程序,比较消耗内存,需要定时重启,进行内存定期释放 0 2 * * *  sudo /sbin/reboot && echo $(date) '重启成功' ...

  9. topcoder srm 551

    div1 250pt 题意:一个长度最多50的字符串,每次操作可以交换相邻的两个字符,问,经过最多MaxSwaps次交换之后,最多能让多少个相同的字符连起来 解法:对于每种字符,枚举一个“集结点”,让 ...

  10. hibernate查询之Criteria实现分页方法(GROOVY语法)

    public int searchTest(String name, Integer pageIndex, List<Test> resultList){ def criteria = T ...