1. 程式人生 > >【BZOJ1014】【JSOI2008】火星人prefix

【BZOJ1014】【JSOI2008】火星人prefix

pla min efi ace 字串 前綴 -s 輸入 bzoj1014

題意:

Description

火星人最近研究了一種操作:求一個字串兩個後綴的公共前綴。比方說,有這樣一個字符串:madamimadam,我們將這個字符串的各個字符予以標號:序號: 1 2 3 4 5 6 7 8 9 10 11 字符 m a d a m i m a d a m 現在,火星人定義了一個函數LCQ(x, y),表示:該字符串中第x個字符開始的字串,與該字符串中第y個字符開始的字串,兩個字串的公共前綴的長度。比方說,LCQ(1, 7) = 5, LCQ(2, 10) = 1, LCQ(4, 7) = 0 在研究LCQ函數的過程中,火星人發現了這樣的一個關聯:如果把該字符串的所有後綴排好序,就可以很快地求出LCQ函數的值;同樣,如果求出了LCQ函數的值,也可以很快地將該字符串的後綴排好序。 盡管火星人聰明地找到了求取LCQ函數的快速算法,但不甘心認輸的地球人又給火星人出了個難題:在求取LCQ函數的同時,還可以改變字符串本身。具體地說,可以更改字符串中某一個字符的值,也可以在字符串中的某一個位置插入一個字符。地球人想考驗一下,在如此復雜的問題中,火星人是否還能夠做到很快地求取LCQ函數的值。

Input

第一行給出初始的字符串。第二行是一個非負整數M,表示操作的個數。接下來的M行,每行描述一個操作。操作有3種,如下所示
1、詢問。語法:Qxy,x,y均為正整數。功能:計算LCQ(x,y)限制:1<=x,y<=當前字符串長度。
2、修改。語法:Rxd,x是正整數,d是字符。功能:將字符串中第x個數修改為字符d。限制:x不超過當前字符串長度。
3、插入:語法:Ixd,x是非負整數,d是字符。功能:在字符串第x個字符之後插入字符d,如果x=0,則在字符串開頭插入。限制:x不超過當前字符串長度

Output

對於輸入文件中每一個詢問操作,你都應該輸出對應的答案。一個答案一行。

題解:

這題本質是簡單題。。。我沒做真的虧爆。。。

沒有修改的最長公共前綴有很經典的二分+哈希的$O(nlogn)$做法,相信大家都會。

考慮如何把這個做法變成可以修改的:

Splay,嗯,沒了。

隨便維護一下hash值即可,查詢依然二分+哈希

代碼:

  1 #include<algorithm>
  2 #include<iostream>
  3 #include<cstring>
  4 #include<cstdio>
  5 #include<cmath>
  6 #include<queue>
  7
#define inf 2147483647 8 #define eps 1e-9 9 #define ha 19260817 10 using namespace std; 11 typedef long long ll; 12 struct node{ 13 int son[2],siz,v,fa; 14 }t[200001]; 15 int n,m,x,y,rt,tot,H[200001],num[200001]; 16 char s[100001],op[5],ch[5]; 17 int lr(int u){ 18 return t[t[u].fa].son[1]==u; 19 } 20 void updata(int u){ 21 t[u].siz=t[t[u].son[0]].siz+t[t[u].son[1]].siz+1; 22 t[u].v=(t[t[u].son[0]].v+(ll)num[u]*H[t[t[u].son[0]].siz]%ha+(ll)t[t[u].son[1]].v*H[t[t[u].son[0]].siz+1]%ha)%ha; 23 } 24 void rotate(int u){ 25 int f=t[u].fa,ff=t[f].fa,ch=lr(u); 26 if(ff)t[ff].son[lr(f)]=u; 27 t[f].son[ch]=t[u].son[ch^1]; 28 t[t[f].son[ch]].fa=f; 29 t[u].son[ch^1]=f; 30 t[f].fa=u; 31 t[u].fa=ff; 32 updata(f); 33 updata(u); 34 } 35 void splay(int u,int g){ 36 for(;t[u].fa!=g;rotate(u)){ 37 int f=t[u].fa; 38 if(t[f].fa!=g)rotate(lr(u)==lr(f)?f:u); 39 } 40 if(!g)rt=u; 41 } 42 int findx(int u,int x){ 43 if(!u)return 0; 44 if(x==t[t[u].son[0]].siz+1)return u; 45 else if(x<t[t[u].son[0]].siz+1)return findx(t[u].son[0],x); 46 else return findx(t[u].son[1],x-t[t[u].son[0]].siz-1); 47 } 48 int build(int l,int r,int f){ 49 if(l>r)return 0; 50 int u=(l+r)/2; 51 t[u].v=num[u]=s[u]-0; 52 t[u].siz=1; 53 t[u].fa=f; 54 t[u].son[0]=build(l,u-1,u); 55 t[u].son[1]=build(u+1,r,u); 56 updata(u); 57 return u; 58 } 59 void ins(int u,int ch){ 60 int x=findx(rt,u); 61 splay(x,0); 62 int y=findx(rt,u+1); 63 splay(y,x); 64 int v=++tot; 65 t[v].v=num[v]=ch; 66 t[v].siz=1; 67 t[y].son[0]=v; 68 t[v].fa=y; 69 updata(y); 70 updata(x); 71 } 72 void chg(int u,int ch){ 73 int x=findx(rt,u); 74 splay(x,0); 75 num[x]=ch; 76 updata(x); 77 } 78 int query(int l,int r){ 79 int x=findx(rt,l-1); 80 splay(x,0); 81 int y=findx(rt,r+1); 82 splay(y,x); 83 return t[t[y].son[0]].v; 84 } 85 int work(int x,int y){ 86 int l=1,r=min(tot-x,tot-y); 87 while(l<r){ 88 int mid=(l+r)/2; 89 if(query(x+1,x+mid)==query(y+1,y+mid))l=mid+1; 90 else r=mid; 91 } 92 return l-1; 93 } 94 int main(){ 95 H[0]=1; 96 for(int i=1;i<=200000;i++)H[i]=H[i-1]*27%ha; 97 scanf("%s%d",s+2,&m); 98 n=strlen(s+2); 99 tot=n+2; 100 rt=build(1,n+2,0); 101 for(int i=1;i<=m;i++){ 102 scanf("%s",op); 103 if(op[0]==Q){ 104 scanf("%d%d",&x,&y); 105 printf("%d\n",work(x,y)); 106 }else if(op[0]==R){ 107 scanf("%d%s",&x,ch); 108 chg(x+1,ch[0]-0); 109 }else{ 110 scanf("%d%s",&x,ch); 111 ins(x+1,ch[0]-0); 112 } 113 } 114 return 0; 115 }

【BZOJ1014】【JSOI2008】火星人prefix