bzoj 2555: SubString 后缀自动机+LCT
2555: SubString
Time Limit: 30 Sec Memory Limit: 512 MBSubmit: 688 Solved: 235
[Submit][Status][Discuss]
Description
懒得写背景了,给你一个字符串init,要求你支持两个操作
(1):在当前字符串的后面插入一个字符串
(2):询问字符串s在当前字符串中出现了几次?(作为连续子串)
你必须在线支持这些操作。
Input
第一行一个数Q表示操作个数
第二行一个字符串表示初始字符串init
接下来Q行,每行2个字符串Type,Str
Type是ADD的话表示在后面插入字符串。
Type是QUERY的话表示询问某字符串在当前字符串中出现了几次。
为了体现在线操作,你需要维护一个变量mask,初始值为0
读入串Str之后,使用这个过程将之解码成真正询问的串TrueStr。
询问的时候,对TrueStr询问后输出一行答案Result
然后mask = mask xor Result
插入的时候,将TrueStr插到当前字符串后面即可。
HINT:ADD和QUERY操作的字符串都需要解压
Output
Sample Input
A
QUERY B
ADD BBABBBBAAB
Sample Output
0
HINT
40 % 的数据字符串最终长度 <= 20000,询问次数<= 1000,询问总长度<= 10000
100 % 的数据字符串最终长度 <= 600000,询问次数<= 10000,询问总长度<= 3000000
新加数据一组--2015.05.20
5月20日,新加数据一组,今天5月21号。我选时间怎么就选的这么优秀。还对着一堆比我慢的程序调了半天的常数。。。
第一次做这类维护right集合大小的题目,right集合大小即子树有用节点的数量,有用节点即不是复制出来的节点。
在昨天以前这个直接暴力维护暴力链加,修改父亲,然而现在就只有LCT了。另外,为啥不全部重测QAQ,不平衡啊。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cassert> using namespace std; #define MAXN 1210000 int pnt[MAXN],ch[MAXN][2],pls[MAXN],val[MAXN]; bool rev[MAXN]; int stack[MAXN],tops=-1; bool is_root(int now) { return !pnt[now] || (ch[pnt[now]][0]!=now && ch[pnt[now]][1]!=now); } void update(int){} void make_reverse(int now) { swap(ch[now][0],ch[now][1]); rev[now]^=1; } void make_plus(int now,int v) { val[now]+=v; pls[now]+=v; } void down(int now) { if (rev[now]) { make_reverse(ch[now][0]); make_reverse(ch[now][1]); rev[now]=0; } if (pls[now]) { make_plus(ch[now][0],pls[now]); make_plus(ch[now][1],pls[now]); pls[now]=0; } } void rotate(int now) { int p=pnt[now],anc=pnt[p]; int dir=ch[p][0]==now; if (!is_root(p)) ch[anc][ch[anc][1]==p]=now; pnt[now]=anc; pnt[ch[now][dir]]=p; ch[p][1-dir]=ch[now][dir]; pnt[p]=now; ch[now][dir]=p; update(p); update(now); } void splay(int now) { int x=now; stack[++tops]=now; while (!is_root(x)) { x=pnt[x]; stack[++tops]=x; } while(~tops) down(stack[tops--]); while (!is_root(now)) { int p=pnt[now],anc=pnt[p]; if (is_root(p)) rotate(now); else if ((ch[anc][0]==p) == (ch[p][0]==now)) rotate(p),rotate(now); else rotate(now),rotate(now); } } int access(int now) { int son=0; while (now) { splay(now); ch[now][1]=son; update(now); son=now; now=pnt[now]; } return son; } bool same_tree(int x,int y) { while (pnt[x])x=pnt[x]; while (pnt[y])y=pnt[y]; return x==y; } void make_root(int now) { make_reverse(access(now)); } void path_plus(int x,int y,int v) { //cout<<"Plus:"<<x<<" "<<y<<endl; assert(same_tree(x,y)); make_root(x); make_plus(access(y),v); } void link(int x,int y) { //cout<<"Link:"<<x<<" "<<y<<endl; assert(!same_tree(x,y)); make_root(x),access(x); make_root(y),access(y); pnt[x]=y; ch[y][1]=x; } void cut(int x,int y) { //cout<<"Cut:"<<x<<" "<<y<<endl; assert(same_tree(x,y)); make_root(x); access(y); ch[x][1]=0; pnt[y]=0; } char str[MAXN],ss[MAXN]; struct sam_node { int nxt[26]; int pnt; int len; }sam[MAXN]; int topsam=1; int last=1; void Add_sam(char ch) { register int p=last; register int np=++topsam; sam[np].len=sam[p].len+1; val[np]=1; while (p && !sam[p].nxt[ch-'A']) { sam[p].nxt[ch-'A']=np; p=sam[p].pnt; } if (!p) { last=np; sam[np].pnt=1; link(np,sam[np].pnt); }else { register int q=sam[p].nxt[ch-'A']; if (sam[q].len==sam[p].len+1) { sam[np].pnt=q; link(sam[np].pnt,np); last=np; }else { register int nq=++topsam; splay(q); val[nq]=val[q]; sam[nq]=sam[q]; link(sam[nq].pnt,nq); sam[nq].len=sam[p].len+1; cut(sam[q].pnt,q); /*ooo*/sam[q].pnt=nq; link(sam[q].pnt,q); /*ooo*/sam[np].pnt=nq; link(sam[np].pnt,np); while (p && sam[p].nxt[ch-'A']==q) { sam[p].nxt[ch-'A']=nq; p=sam[p].pnt; } last=np; } } path_plus(1,sam[np].pnt,1); } char curs[MAXN];int totc=0; /* void dfs_sam(int now) { if (sam[now].flag) printf("%s\n",curs); for (int i=0;i<26;i++) { if (!sam[now].nxt[i])continue; curs[totc++]=(char)(i+'A'); dfs_sam(sam[now].nxt[i]); curs[--totc]='\0'; } }*/ int find_sam(char *str) { int now=1; while (*str) { if (!sam[now].nxt[*str-'A'])return 0; assert(sam[now].nxt[*str-'A']); now=sam[now].nxt[*str-'A']; str++; } make_root(now); access(now); return val[now]; } void Decode(char* str,int len,int mask) { for (register int i=0;i<len;i++) { mask=(mask*131+i)%len; swap(str[i],str[mask]); } } char opt[20]; char cc[MAXN]; int main() { freopen("input.txt","r",stdin); int n,m,x,y,z; scanf("%d\n",&m); scanf("%s",str); int l=strlen(str); for (int i=0;i<l;i++) Add_sam(str[i]); /* for (int i=last;i;i=sam[i].pnt)sam[i].flag=true; dfs_sam(1); for (int i=0;i<l;i++)find_sam(str+i);*/ int lastans=0; for (int i=0;i<m;i++) { scanf("%s %s\n",opt,cc); int t; t=strlen(cc); Decode(cc,t,lastans); if (opt[0]=='Q') { int now=0; printf("%d\n",t=find_sam(cc)); lastans^=t; }else { int t=strlen(cc); for (int i=0;i<t;i++) Add_sam(cc[i]); } } }
本博客已停用,新博客地址:http://mhy12345.xyz