【bzoj1014】 JSOI2008—火星人prefix
http://www.lydsy.com/JudgeOnline/problem.php?id=1014 (题目链接)
题意
给出一个字符串,要求维护这些操作:询问后缀x与后缀y的LCQ(最长公共前缀),在第k个字符后插入一个字符,将第k个字符改成另一个字符。
Solution
对于修改与插入操作,我们用splay维护。考虑怎么求解LCQ。
我们可以将字符串hash,然后平衡树上每一个节点的hash值就代表的该区间的hash值,毫无疑问,这是可以向上更新的。于是问题就解决了。
细节
注意splay中update的顺序。hash的进制要取好,不能比一位上的数范围小。hash值相乘的时候记得开long long。
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 | #include<algorithm> #include<iostream> #include<cstdlib> #include<cstring> #include<cstdio> #include<cmath> #define LL long long #define inf 2147483640 #define MOD 9875321 #define Pi acos(-1.0) #define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout); using namespace std; const int maxn=150010; int tr[maxn][2],fa[maxn],id[maxn],size[maxn]; int v[maxn],h[maxn],bin[maxn]; int n,rt,sz,q; char s[maxn]; void update( int k) { int l=tr[k][0],r=tr[k][1]; size[k]=size[l]+size[r]+1; h[k]=h[l]+(LL)v[k]*bin[size[l]]%MOD+(LL)bin[size[l]+1]*h[r]%MOD; h[k]%=MOD; } void rotate( int x, int &k) { int y=fa[x],z=fa[y],l,r; l=tr[y][1]==x;r=l^1; if (y==k) k=x; else tr[z][tr[z][1]==y]=x; fa[x]=z;fa[y]=x;fa[tr[x][r]]=y; tr[y][l]=tr[x][r];tr[x][r]=y; update(y);update(x); } void splay( int x, int &k) { while (x!=k) { int y=fa[x],z=fa[y]; if (y!=k) { if ((tr[z][0]==y) ^ (tr[y][0]==x)) rotate(x,k); else rotate(y,k); } rotate(x,k); } } int find( int k, int x) { int l=tr[k][0],r=tr[k][1]; if (size[l]+1==x) return k; else if (size[l]>=x) return find(l,x); else return find(r,x-size[l]-1); } void insert( int k, int val) { int x=find(rt,k+1),y=find(rt,k+2); splay(x,rt);splay(y,tr[x][1]); int z=++sz;tr[y][0]=z;fa[z]=y;v[z]=val; update(z);update(y);update(x); } int query( int k, int val) { int x=find(rt,k),y=find(rt,k+val+1); splay(x,rt);splay(y,tr[x][1]); return h[tr[y][0]]; } int solve( int x, int y) { int l=1,r=min(sz-x,sz-y)-1,ans=0; while (l<=r) { int mid=(l+r)>>1; if (query(x,mid)==query(y,mid)) l=mid+1,ans=mid; else r=mid-1; } return ans; } void build( int l, int r, int f) { if (l>r) return ; int mid=(l+r)>>1,now=id[mid],last=id[f]; if (l==r) { v[now]=h[now]=s[mid]- 'a' +1; fa[now]=last;size[now]=1; tr[last][mid>=f]=now; return ; } build(l,mid-1,mid);build(mid+1,r,mid); v[now]=s[mid]- 'a' +1;fa[now]=last;update(now); tr[last][mid>=f]=now; } int main() { scanf ( "%s" ,s+2); n= strlen (s+2); bin[0]=1; for ( int i=1;i<maxn;i++) bin[i]=bin[i-1]*31%MOD; for ( int i=1;i<=n+2;i++) id[i]=i; build(1,n+2,0);rt=(n+3)>>1;sz=n+2; scanf ( "%d" ,&q); while (q--) { int x,y; char ch[10]; scanf ( "%s" ,ch); scanf ( "%d" ,&x); if (ch[0]== 'Q' ) scanf ( "%d" ,&y), printf ( "%d\n" ,solve(x,y)); if (ch[0]== 'R' ) { scanf ( "%s" ,ch); x=find(rt,x+1);splay(x,rt); v[rt]=ch[0]- 'a' +1;update(rt); } if (ch[0]== 'I' ) scanf ( "%s" ,ch),insert(x,ch[0]- 'a' +1); } return 0; } |
This passage is made by MashiroSky.
分类:
数据结构--splay
, 字符串--hash
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】博客园携手 AI 驱动开发工具商 Chat2DB 推出联合终身会员
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET 依赖注入中的 Captive Dependency
· .NET Core 对象分配(Alloc)底层原理浅谈
· 聊一聊 C#异步 任务延续的三种底层玩法
· 敏捷开发:如何高效开每日站会
· 为什么 .NET8线程池 容易引发线程饥饿
· 一个适用于 .NET 的开源整洁架构项目模板
· API 风格选对了,文档写好了,项目就成功了一半!
· 【开源】C#上位机必备高效数据转换助手
· .NET 9.0 使用 Vulkan API 编写跨平台图形应用
· MyBatis中的 10 个宝藏技巧!