BZOJ2555:SubString(SAM,LCT)
Description
懒得写背景了,给你一个字符串init,要求你支持两个操作
(1):在当前字符串的后面插入一个字符串
(2):询问字符串s在当前字符串中出现了几次?(作为连续子串)
你必须在线支持这些操作。
Input
第一行一个数Q表示操作个数
第二行一个字符串表示初始字符串init
接下来Q行,每行2个字符串Type,Str
Type是ADD的话表示在后面插入字符串。
Type是QUERY的话表示询问某字符串在当前字符串中出现了几次。
为了体现在线操作,你需要维护一个变量mask,初始值为0
读入串Str之后,使用这个过程将之解码成真正询问的串TrueStr。
询问的时候,对TrueStr询问后输出一行答案Result
然后mask=maskxorResult
插入的时候,将TrueStr插到当前字符串后面即可。
HINT:ADD和QUERY操作的字符串都需要解压
长度 <= 600000,询问次数<= 10000,询问总长度<= 3000000
新加数据一组--2015.05.20
Output
Sample Input
2
A
QUERY B
ADD BBABBBBAAB
A
QUERY B
ADD BBABBBBAAB
Sample Output
0
Solution
可以发现这个题如果不是多组询问的话,就是求SAM的right集合的大小的裸题
不过一边插入一边询问很显然是无法像原来一样等全部字符都插入后再排序求right集合大小的
不过根据right集合的定义,其实我们可以发现一个点的right集合大小就是子树的np节点的个数
这玩意儿只需要用LCT维护子树权值和就好了
不过一边插入一边询问很显然是无法像原来一样等全部字符都插入后再排序求right集合大小的
不过根据right集合的定义,其实我们可以发现一个点的right集合大小就是子树的np节点的个数
这玩意儿只需要用LCT维护子树权值和就好了
Code
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #define N (1200000+1000) 5 using namespace std; 6 7 int Father[N],Son[N][2],Size[N],Si[N],Rev[N],R[N],T,mask; 8 char s[N],opt[10]; 9 10 int Get(int x){return Son[Father[x]][1]==x;} 11 int Is_root(int x){return Son[Father[x]][0]!=x && Son[Father[x]][1]!=x;} 12 void Update(int x){Size[x]=Si[x]+Size[Son[x][0]]+Size[Son[x][1]]+R[x];} 13 14 void Pushdown(int x) 15 { 16 if (x && Rev[x]) 17 { 18 if (Son[x][0]) Rev[Son[x][0]]^=1; 19 if (Son[x][1]) Rev[Son[x][1]]^=1; 20 swap(Son[x][0],Son[x][1]); 21 Rev[x]=0; 22 } 23 } 24 25 void Rotate(int x) 26 { 27 int wh=Get(x); 28 int fa=Father[x],fafa=Father[fa]; 29 if (!Is_root(fa)) Son[fafa][Son[fafa][1]==fa]=x; 30 Son[fa][wh]=Son[x][wh^1]; Father[fa]=x; 31 Son[x][wh^1]=fa; Father[x]=fafa; 32 if (Son[fa][wh]) Father[Son[fa][wh]]=fa; 33 Update(fa); Update(x); 34 } 35 36 void Push(int x){if (!Is_root(x)) Push(Father[x]); Pushdown(x);} 37 void Splay(int x) 38 { 39 Push(x); 40 for (int fa; !Is_root(x); Rotate(x)) 41 if (!Is_root(fa=Father[x])) 42 Rotate(Get(fa)==Get(x)?fa:x); 43 } 44 45 void Access(int x) 46 { 47 for (int y=0; x; y=x,x=Father[x]) 48 { 49 Splay(x); 50 Si[x]+=Size[Son[x][1]]; Si[x]-=Size[y]; 51 Son[x][1]=y; Update(x); 52 } 53 } 54 55 void Make_root(int x){Access(x); Splay(x); Rev[x]^=1;} 56 int Find_root(int x){Access(x); Splay(x); while (Son[x][0]) x=Son[x][0]; return x;} 57 void Link(int x,int y){Make_root(x); Make_root(y); Father[x]=y; Si[y]+=Size[x]; Update(y);} 58 void Cut(int x,int y){Make_root(x); Access(y); Splay(y); Son[y][0]=Father[x]=0; Update(y);} 59 60 struct SAM 61 { 62 int fa[N],son[N][28],step[N]; 63 int p,q,np,nq,last,cnt; 64 SAM(){last=++cnt;} 65 66 void Insert(int x) 67 { 68 p=last; np=last=++cnt; step[np]=step[p]+1; R[np]=1; 69 while (p && !son[p][x]) son[p][x]=np,p=fa[p]; 70 if (!p) fa[np]=1,Link(np,1); 71 else 72 { 73 q=son[p][x]; 74 if (step[p]+1==step[q]) fa[np]=q,Link(np,q); 75 else 76 { 77 nq=++cnt; step[nq]=step[p]+1; 78 memcpy(son[nq],son[q],sizeof(son[q])); 79 Link(nq,fa[q]); Cut(q,fa[q]); Link(q,nq); Link(np,nq); 80 fa[nq]=fa[q]; fa[q]=fa[np]=nq; 81 while (son[p][x]==q) son[p][x]=nq,p=fa[p]; 82 } 83 } 84 } 85 int Query(char s[]) 86 { 87 Make_root(1); 88 int now=1, len=strlen(s); 89 for (int i=0; i<len; ++i) 90 if (son[now][s[i]-'A']) now=son[now][s[i]-'A']; 91 else return 0; 92 Access(now); Splay(now); 93 return Size[now]-Size[Son[now][0]]; 94 } 95 }SAM; 96 97 void Decode(char *s,int mask) 98 { 99 int len=strlen(s); 100 for(int i=0; i<len; ++i) 101 { 102 mask=(mask*131+i)%len; 103 swap(s[i],s[mask]); 104 } 105 } 106 107 int main() 108 { 109 scanf("%d",&T); 110 scanf("%s",s); 111 int len=strlen(s); 112 for (int i=0; i<len; ++i) 113 SAM.Insert(s[i]-'A'); 114 while (T--) 115 { 116 scanf("%s%s",opt,s); 117 int len=strlen(s); 118 Decode(s,mask); 119 if (opt[0]=='A') 120 for (int i=0; i<len; ++i) 121 SAM.Insert(s[i]-'A'); 122 else 123 { 124 int ans=SAM.Query(s); 125 printf("%d\n",ans); 126 mask^=ans; 127 } 128 } 129 }