题目: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+5,xm=250005;
int n,m,rt,fa[xm],c[xm][2],siz[xm];
ll pw[xm],hsh[xm];
char s[xn],ch[xn];
void pushup(int x)
{int ls=c[x][0],rs=c[x][1];siz[x]=siz[ls]+siz[rs]+1;hsh[x]=hsh[ls]*pw[siz[rs]+1]+(s[x]-'a'+1)*pw[siz[rs]]+hsh[rs];
}
void rotate(int x,int &f)
{int y=fa[x],z=fa[y],d=(c[y][1]==x);if(z)c[z][c[z][1]==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][0]==x)^(c[z][0]==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'+1,siz[l]=1;else build(l,mid-1,mid),build(mid+1,r,mid);fa[mid]=lst; c[lst][mid>lst]=mid; pushup(mid);
}
int find(int x,int k)//找到 k 位置
{while(1){int p=c[x][0],q=c[x][1];if(siz[p]+1==k)return x;else if(siz[p]+1<k)x=q,k-=siz[p]+1;else x=p;}
}
void insert(int pos,char d)
{s[++n]=d; hsh[n]=d-'a'+1;int x=find(rt,pos+1);//+1 因为有左右的'a'splay(x,0); x=find(rt,pos+2); splay(x,rt);//
//    splay(x,rt); x=find(rt,pos+2); splay(x,c[rt][1]);c[x][0]=n; siz[n]=1; fa[n]=x;pushup(x); pushup(rt);
}
void change(int pos,char d)
{int x=find(rt,pos+1);splay(x,0);//
//    splay(x,rt);s[x]=d; pushup(x);
}
bool ck(int l,int r,int k)
{ll h1=0,h2=0;
//    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,0);x=find(rt,l+k+1); splay(x,rt);h1=hsh[c[x][0]];
//    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,0);x=find(rt,r+k+1); splay(x,rt);h2=hsh[c[x][0]];return h1==h2;
}
int query(int x,int l,int r)
{int ll=0,rr=n-2-max(l,r)+1,ret=0;while(ll<=rr){int md=((ll+rr)>>1);if(ck(l,r,md))ret=md,ll=md+1;else rr=md-1;}return ret;
}
void init()
{n=strlen(s+2); pw[0]=1;for(int i=1;i<=xm-5;i++)pw[i]=pw[i-1]*27;s[1]=s[n+2]='a'; build(1,n+2,0); n=n+2; rt=(n+1)/2;//
}
int main()
{scanf("%s",s+2); init();scanf("%d",&m);for(int i=1,x,y;i<=m;i++){scanf("%s%d",ch,&x);if(ch[0]=='I')scanf("%s",ch),insert(x,ch[0]);if(ch[0]=='R')scanf("%s",ch),change(x,ch[0]);if(ch[0]=='Q')scanf("%d",&y),printf("%d\n",query(rt,x,y));}return 0;
}

转载于:https://www.cnblogs.com/Zinn/p/9724346.html

bzoj 1014 火星人prefix —— splay+hash相关推荐

  1. BZOJ 1014 火星人prefix

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

  2. 【BZOJ1014】【JSOI2008】火星人prefix Splay处理区间,hash+dichotomy(二分)check出解...

    题意不赘述了,太清晰了. 说题解:首先依据原字符串建立SPT.首尾建议多加一个空白字符. 给一个树构图,依照平衡树的前后大小顺序性质能够使它们始终维持为一个序列,而且能够通过rank找到序列的第k个. ...

  3. 【BZOJ1014】【JSOI2008】火星人prefix Splay处理区间,hash+dichotomy(二分)check出解

    题意不赘述了,太清晰了. 说题解:首先根据原字符串建立SPT,首尾建议多加一个空白字符. 给一个树构图,按照平衡树的前后大小顺序性质可以使它们始终维持为一个序列,并且可以通过rank找到序列的第k个. ...

  4. bzoj 1014: [JSOI2008]火星人prefix(splay维护区间+Hash+二分)

    1014: [JSOI2008]火星人prefix Time Limit: 10 Sec  Memory Limit: 162 MB Submit: 7588  Solved: 2429 [Submi ...

  5. splay/fhq-treap 问卷调查反馈—— [JSOI2008]火星人prefix(splay),Strange Queries(fhq-treap)

    文章目录 [JSOI2008]火星人prefix Strange Queries [JSOI2008]火星人prefix BZOJ1014 思路很好想,哈希字符串即可 只是平衡树的码量大 注意因为sp ...

  6. BZOJ1014: [JSOI2008]火星人prefix

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

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

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

  8. 【BZOJ1014】【tyvj3486】火星人prefix,Splay+字符串hash

    Time:2016.07.19 Author:xiaoyimi 转载注明出处谢谢 传送门1 传送门2 思路&&注意: LCP这个东西可以用后缀数组,扩展kmp什么的来做 这里加上了插入 ...

  9. BZOJ 1014 [JSOI2008]火星人prefix

    splay维护hash值: 看到大佬们都在打数据结构,我说好的不打数据结构又自己打脸了. 为了写这个昨天还特意去打了Splay的普通平衡树,自从我学会Treap以来第一次用splayA掉普通平衡树QA ...

最新文章

  1. 学术前沿 | 图像质量量化评估标准综述
  2. 二、linux最小驱动
  3. Android Gradle manifestPlaceholders 占位符详解
  4. 1052 卖个萌 (20 分)
  5. Laravel核心解读--Session源码解析
  6. Delphi实现点击按钮触发选择项, 进而实现不同的分支功能
  7. 《Apache Kafka 实战》读书笔记-认识Apache Kafka
  8. PKI世界中两个知名的情侣 Alice和Bob
  9. android 多线程 js,android中的jstack,见见线程都在干嘛
  10. mysql判断时间是否在某个区间_如何正确理解 RT 并监控 MySQL 的响应时间
  11. MvvmCross框架在XamarinForms中的使用入门
  12. csdn积分如何获取攻略
  13. oracle数据转换,Oracle数据库转换函数
  14. 信捷PLC之C函数编程(一)
  15. Windows文件扩展名
  16. 吉首大学校赛 A SARS病毒 (欧拉降幂)
  17. INSTALL_PARSE_FAILED_NO_CERTIFICATES 解决办法
  18. 计算机基本概念反思,计算机基础教学反思
  19. Rasa课程、Rasa培训、Rasa面试、Rasa实战系列之Gavin大咖免费公益课程Rasa Paper论文解析核心版
  20. Python——飞机大战(day10)

热门文章

  1. python做客户端适合吗_为了选出最合适的 HTTP 客户端,我做了个测评
  2. 单击托盘显示菜单mfc_PhotoShop制作滚动菜单栏教程
  3. html5触摸界面设计与开发_原生APP的开发步骤主要分为哪些?
  4. mysql mssql 性能对比_MySQL最新版8.0与5.7之性能对比,看看它是如何改进的
  5. collection.stream()以及collect()方法
  6. 判断浏览器是否支持websocket的方法
  7. mysql row 格式binlog 恢复_为什么要把MySQL的binlog格式修改为row
  8. swoole redis
  9. Linux基础命令之sed用法
  10. 将Java项目从maven迁移到gradle