传送门

如果没有修改的操作,很容易想到 后缀数组 倍增+哈希求 LCQ

如果有修改呢,哈希值就会发生改变,这时我们就要找一种数据结构来维护哈希值

emm...改字符和插入字符....

显然可以用平衡树维护

所以总体思路就是用平衡树维护哈希值,然后倍增+哈希求LCQ

怎么维护哈希值很容易想到,直接看具体代码好了

inline void pushup(int x)
{int &l=ch[x][0],&r=ch[x][1];sz[x]=sz[l]+sz[r]+1;t[x]=t[r]+pw[sz[r]]*val[x]+t[l]*pw[sz[r]+1];//t存哈希值//pw存底数的倍数
}

平衡树更新节点操作

提取一段区间的哈希值也不难,把左边界节点-1旋到根,右边界节点+1旋到根的右儿子

那么哈希值就是根的右儿子的左儿子的哈希值

哈希直接用自然溢出哈希就好了,(据说BZOJ卡常数?)

这题开始我是想二分写的,然后发现很多细节要搞

最后改成倍增就好写了

其他都是平衡树的基本操作了

因为我们可能会访问到1节点-1和n节点+1,所以要多插入两个虚节点 0 号和 n+1 号

具体实现时一定要记得有多两个节点

一开始直接建一颗标准的平衡树就好了

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
typedef unsigned long long ull;
inline int read()
{int x=0,f=1; char ch=getchar();while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); }while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }return x*f;
}
const int N=2e5+7,base=233;
ull pw[N],t[N];//自然溢出
int sz[N],fa[N],ch[N][2],val[N],rt,cnt;
inline void pushup(int x)//维护哈希值和子树大小
{int &l=ch[x][0],&r=ch[x][1];sz[x]=sz[l]+sz[r]+1;t[x]=t[r]+pw[sz[r]]*val[x]+t[l]*pw[sz[r]+1];
}
inline void rotate(int x,int &k)
{int y=fa[x],z=fa[y],d=(ch[y][1]==x);if(y!=k) ch[z][(ch[z][1])==y]=x;else k=x;fa[x]=z; fa[y]=x; fa[ch[x][d^1]]=y;ch[y][d]=ch[x][d^1]; ch[x][d^1]=y;pushup(y); pushup(x);
}
inline void Splay(int x,int &k)
{while(x!=k){int y=fa[x],z=fa[y];if(y!=k){if(ch[y][1]==x ^ ch[z][1]==y) rotate(x,k);else rotate(y,k);}rotate(x,k);}
}
inline int find(int k)//找到区间中第k名的节点并返回它的编号
{int now=rt;while(1){if(ch[now][0]&&k<=sz[ch[now][0]]) { now=ch[now][0]; continue; }if(k>sz[ ch[now][0] ]+1) k-=sz[ ch[now][0] ]+1,now=ch[now][1];else return now;}
}
inline int get_hash(int l,int r)//从树中取出闭区间[l,r]哈希值
{int x=find(r+1);Splay(find(l-1),rt); Splay(x,ch[rt][1]);return t[ch[x][0]];
}
inline int Q(int x,int y)//倍增求LCQ
{int res=0; if(x<y) swap(x,y);for(int i=17;i>=0;i--){if(x+(1<<i)-1>=sz[rt]) continue;//注意-1和>=,>=是因为有虚节点在最后if( get_hash(x,x+(1<<i)-1)!=get_hash(y,y+(1<<i)-1) ) continue;//注意减1,闭区间res|=(1<<i); x+=1<<i; y+=1<<i;//此处不用减1
    }return res;
}
inline void change(int k,int c)//修改操作
{int x=find(k);//找到位置val[x]=c; Splay(x,rt);//修改后记得Splay一波来调整整颗树的形态和数据
}
inline void ins(int k,int c)//插入操作
{int x=find(k);//先找到第k的节点if(!ch[x][1]) ch[x][1]=++cnt;//注意特判else//找它右边子树内最左的节点x,插入的位置就是x的左儿子
    {x=ch[x][1]; while(ch[x][0]) x=ch[x][0];ch[x][0]=++cnt;}fa[cnt]=x; val[cnt]=c; sz[cnt]=1;Splay(cnt,rt);//记得Splay一波来调整整颗树的形态和数据
}
inline void build(int l,int r,int f)//一开始先建一颗标准平衡树
{int mid=l+r>>1; fa[mid]=f; ch[f][mid>f]=mid;if(mid>l) build(l,mid-1,mid);if(mid<r) build(mid+1,r,mid);pushup(mid);
}
int n,m;
char s[N];
int main()
{scanf("%s",s); cnt=n=strlen(s)+2;//注意此时cnt=nm=read();pw[0]=1; for(int i=1;i<N;i++) pw[i]=pw[i-1]*base;//初始化pwfor(int i=2;i<n;i++) val[i]=s[i-2]-'a',sz[i]=1;sz[1]=sz[n]=1; val[1]=val[n]=27;//两个虚节点rt=1+n>>1; build(1,n,0);char ss[5],c[5]; int a,b;while(m--){scanf("%s",ss);if(ss[0]=='Q'){a=read(); b=read();printf("%d\n",Q(a+1,b+1));//记得+1continue;}a=read(); scanf("%s",c);if(ss[0]=='R') change(a+1,c[0]-'a');//a+1else ins(a+1,c[0]-'a');//a+1
    }return 0;
}

转载于:https://www.cnblogs.com/LLTYYC/p/10113683.html

BZOJ 1014: [JSOI2008]火星人prefix相关推荐

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

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

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

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

  3. BZOJ 1014 [JSOI2008]火星人prefix

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

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

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

  5. BZOJ1014: [JSOI2008]火星人prefix

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

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

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

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

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

  8. BZOJ 1567: [JSOI2008]Blue Mary的战役地图

    二次联通门 : BZOJ 1567: [JSOI2008]Blue Mary的战役地图 /*BZOJ 1567: [JSOI2008]Blue Mary的战役地图社会我栋哥人怂P话多暴力能A题正解能W ...

  9. BZOJ 1014 火星人prefix

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

  10. bzoj 1014 火星人prefix —— splay+hash

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1014 用 splay 维护字符串上不同位置的哈希值还是第一次... 具体就是每个节点作为位置 ...

最新文章

  1. Android开发之大位图压缩水印处理
  2. 无线覆盖带机量比较大的型号推荐
  3. 如何在window系统VS中设置boost编程环境
  4. Data Lake Analytics: 使用DataWorks来调度DLA任务
  5. 自学JAVA5.18
  6. 漫画:Java如何实现热更新?
  7. java list api_Java核心API -- 6(Collection集合List、Set、ArrayList、HashSet)
  8. 学习FFmpeg API – 解码视频
  9. 阿里巴巴与小毛驴的故事——贪心算法
  10. python利用字典破解WIFI密码
  11. 毫秒级超低延时直播产品实测(PRTC直播/webRTC直播)
  12. echarts 弹出放大_vue中使用v-chart时放大缩小屏幕,echarts图自适应
  13. Mysql(免安装版)安装、配置与卸载
  14. 谈一谈Normalize.css
  15. 【VB】中CInt()、Fix()、Int()的区别
  16. zotero+坚果云
  17. 组合数的几种计算方法
  18. kali安装Netspeed
  19. java espresso车架_Espresso 学习
  20. sitemap-php生成网站地图

热门文章

  1. Ubuntu安装RabbitMQ及RabbitMQ基于使用
  2. jQuery操作DOM节点的相关方法
  3. 【渝粤教育】21秋期末考试社会学概论10082k1
  4. 【渝粤教育】国家开放大学2018年春季 8612-22T传染病护理学 参考试题
  5. LeetCode刷题系列(二)二分查找、二叉排序树 的应用
  6. “人生没有一桩幸福不要付代价的。东边占了便宜,西边就得吃亏些。”--《傅雷家书》
  7. 导出函数__declspec(dllexport)
  8. autotools工具介绍
  9. 2018/06/30这段时间的随笔记忆:遇到概念模糊的js问题
  10. 【iCore4 双核心板_ARM】例程二十九:SD_IAP_FPGA实验——更新升级FPGA