[JSOI2008]火星人prefix
[JSOI2008]火星人prefix
題目
火星人最近研究了一種操作:求一個字串兩個後綴的公共前綴。比方說,有這樣一個字符串: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
對於輸入文件中每一個詢問操作,你都應該輸出對應的答案。一個答案一行。
SAMPLE
INPUT
madamimadam
7
Q 1 7
Q 4 8
Q 10 11
R 3 a
Q 1 7
I 10 a
Q 2 11OUTPUT
5
1
0
2
1
解題報告
無旋$Treap$+$Hash$+二分答案
用無旋$Treap$或者$Splay$維護$Hash$,查詢時二分答案,取區間$Hash$值驗證
1 /************************************************************** 2 Problem: 1014 3 User: MAFIAView Code4 Language: C++ 5 Result: Accepted 6 Time:10612 ms 7 Memory:5628 kb 8 ****************************************************************/ 9 10 #include<iostream> 11 #include<cstring> 12 #include<cstdlib> 13 #include<cstdio> 14 #include<ctime> 15 using namespace std; 16 inline int read(){ 17 int sum(0); 18 char ch(getchar()); 19 while(ch<‘0‘||ch>‘9‘) 20 ch=getchar(); 21 while(ch>=‘0‘&&ch<=‘9‘){ 22 sum=sum*10+ch-‘0‘; 23 ch=getchar(); 24 } 25 return sum; 26 } 27 int n,m,top; 28 typedef unsigned long long L; 29 const L p=2333; 30 L xp[100005]; 31 struct node{ 32 int key,size; 33 L has; 34 char c; 35 node *ch[2]; 36 node(char x=0):size(1),key(rand()),c(x),has(x){ 37 ch[0]=ch[1]=NULL; 38 } 39 inline void pushup(); 40 }*root,*st[100005]; 41 typedef pair<node*,node*>pii; 42 inline int get_size(node *x){ 43 if(x==NULL) 44 return 0; 45 return x->size; 46 } 47 inline L get_hash(node *x){ 48 if(x==NULL) 49 return 0; 50 return x->has; 51 } 52 inline void node::pushup(){ 53 size=1; 54 size+=get_size(ch[0])+get_size(ch[1]); 55 has=get_hash(ch[0])*xp[get_size(ch[1])+1]+c*xp[get_size(ch[1])]+get_hash(ch[1]); 56 } 57 char s[100005]; 58 inline node* build(){ 59 node *x,*las; 60 for(int i=1;i<=n;i++){ 61 x=new node(s[i]); 62 las=NULL; 63 while(top&&st[top]->key>x->key){ 64 st[top]->pushup(); 65 las=st[top]; 66 st[top--]=NULL; 67 } 68 if(top) 69 st[top]->ch[1]=x; 70 x->ch[0]=las; 71 st[++top]=x; 72 } 73 while(top) 74 st[top--]->pushup(); 75 return st[1]; 76 } 77 inline node* merge(node *x,node *y){ 78 if(x==NULL) 79 return y; 80 if(y==NULL) 81 return x; 82 if(x->key<y->key){ 83 // x->pushdown(); 84 x->ch[1]=merge(x->ch[1],y); 85 x->pushup(); 86 return x; 87 } 88 else{ 89 // y->pushdown(); 90 y->ch[0]=merge(x,y->ch[0]); 91 y->pushup(); 92 return y; 93 } 94 } 95 inline pii split(node *x,int k){ 96 if(!x) 97 return pii(NULL,NULL); 98 pii y; 99 // x->pushdown(); 100 if(get_size(x->ch[0])>=k){ 101 y=split(x->ch[0],k); 102 x->ch[0]=y.second; 103 x->pushup(); 104 y.second=x; 105 } 106 else{ 107 y=split(x->ch[1],k-get_size(x->ch[0])-1); 108 x->ch[1]=y.first; 109 x->pushup(); 110 y.first=x; 111 } 112 return y; 113 } 114 inline void insert(char x,int k){ 115 pii tp(split(root,k)); 116 node *tmp(new node(x)); 117 root=merge(merge(tp.first,tmp),tp.second); 118 ++n; 119 } 120 inline void change(char x,int k){ 121 pii s1(split(root,k)); 122 pii s2(split(s1.first,k-1)); 123 s2.second->has=s2.second->c=x; 124 s1.first=merge(s2.first,s2.second); 125 root=merge(s1.first,s1.second); 126 } 127 inline L gethash(int x,int y){ 128 if(x>y) 129 return 0; 130 pii s1(split(root,y)); 131 pii s2(split(s1.first,x-1)); 132 L ret(s2.second->has); 133 s1.first=merge(s2.first,s2.second); 134 root=merge(s1.first,s1.second); 135 return ret; 136 } 137 inline int query(int x,int y){ 138 int l(0),r(min(n-x+1,n-y+1)),mid,ans(0); 139 while(l<=r){ 140 mid=(l+r)>>1; 141 if(gethash(x,x+mid-1)==gethash(y,y+mid-1)) 142 ans=mid,l=mid+1; 143 else 144 r=mid-1; 145 } 146 return ans; 147 } 148 char op[2],ch[2]; 149 int main(){ 150 xp[0]=1; 151 for(int i=1;i<=100000;++i) 152 xp[i]=xp[i-1]*p; 153 scanf("%s",s+1); 154 n=strlen(s+1); 155 root=build(); 156 m=read(); 157 for(int i=1;i<=m;i++){ 158 scanf("%s",op); 159 if(op[0]==‘Q‘){ 160 int x(read()),y(read()); 161 printf("%d\n",query(x,y)); 162 } 163 if(op[0]==‘R‘){ 164 int x(read()); 165 scanf("%s",ch); 166 change(ch[0],x); 167 } 168 if(op[0]==‘I‘){ 169 int x(read()); 170 scanf("%s",ch); 171 insert(ch[0],x); 172 } 173 } 174 }
大視野上不要用$srand$,親測$RE$= =
[JSOI2008]火星人prefix