*一道题20
$n \leq 200000$的字符串,$m \leq 200000$次操作:1,末尾加一个字符;2,末尾删一个字符;3,一个区间中,问某个串(新给的)出现次数。强制在线。
并不会。
首先可以通过$nm$的复杂度成功拿到20分。
其次可以写一个不带加字符的:建个后缀树,然后查询就是查:后缀树的一个子树里,有多少编号在一定区间(注意不是询问的区间,右端点需要调整)的后缀。不修改的在线二维数点可以用主席树。也只有20分。
1 //#include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 //#include<time.h> 5 //#include<complex> 6 //#include<set> 7 //#include<queue> 8 //#include<vector> 9 #include<algorithm> 10 #include<stdlib.h> 11 using namespace std; 12 13 #define LL long long 14 int qread() 15 { 16 char c; int s=0,f=1; while ((c=getchar())<'0' || c>'9') (c=='-') && (f=-1); 17 do s=s*10+c-'0'; while ((c=getchar())>='0' && c<='9'); return s*f; 18 } 19 20 //Pay attention to '-' , LL and double of qread!!!! 21 22 int n,lq; 23 #define maxn 400011 24 char s[maxn],p[maxn]; 25 26 int getnum(char c) {if (c>='a' && c<='z') return c-'a'; return c-'A'+26;} 27 int getch(int x) {if (x<26) return 'a'+x; return 'A'+x-26;} 28 29 int fail[maxn]; 30 void solve1() 31 { 32 int op,x,y,last=0; char c; 33 while (lq--) 34 { 35 op=qread(); 36 if (op==1) 37 { 38 while (((c=getchar())<'a' || c>'z') && (c<'A' || c>'Z')); 39 c=getch((getnum(c)+last)%52); 40 s[++n]=c; 41 } 42 else if (op==2) n--; 43 else 44 { 45 x=qread()^last; y=qread()^last; 46 fail[1]=fail[2]=1; 47 int now=1; 48 while (((c=getchar())<'a' || c>'z') && (c<'A' || c>'Z')); 49 p[now]=getch((getnum(c)+last)%52); 50 while (((c=getchar())>='a' && c<='z') || (c>='A' && c<='Z')) 51 { 52 p[++now]=getch((getnum(c)+last)%52); 53 int j=fail[now]; 54 while (j>1 && p[j]!=p[now]) j=fail[j]; 55 fail[now+1]=p[j]==p[now]?j+1:1; 56 } 57 int ans=0; 58 for (int i=x,j=1;i<=y;i++) 59 { 60 while (j>1 && p[j]!=s[i]) j=fail[j]; 61 if (p[j]==s[i]) j++; 62 if (j>now) {ans++; j=fail[j];} 63 } 64 printf("%d\n",ans); 65 last=ans; 66 } 67 } 68 } 69 70 struct Edge{int to,next;}; 71 struct SAM 72 { 73 struct Node{int ch[52],pos,Max,pre;}a[maxn]; 74 int size,last; 75 int val[maxn],vvv[maxn]; 76 SAM() {a[0].pre=-1; a[0].pos=a[0].Max=size=0; last=Time=0; le=2;} 77 void insert(int id,int pos) 78 { 79 int x=++size,y=last; 80 a[x].pos=pos; a[x].Max=n-pos+1; last=x; val[x]=pos; 81 for (;~y && !a[y].ch[id];y=a[y].pre) a[y].ch[id]=x; 82 if (!~y) a[x].pre=0; 83 else if (a[a[y].ch[id]].Max==a[y].Max+1) a[x].pre=a[y].ch[id]; 84 else 85 { 86 int w=++size,z=a[y].ch[id]; a[w]=a[z]; a[w].Max=a[y].Max+1; a[w].pos=pos; 87 a[z].pre=a[x].pre=w; 88 for (;~y && a[y].ch[id]==z;y=a[y].pre) a[y].ch[id]=w; 89 } 90 } 91 Edge edge[maxn]; int first[maxn],le; 92 void in(int x,int y) {Edge &e=edge[le]; e.to=y; e.next=first[x]; first[x]=le++;} 93 int ll[maxn],rr[maxn],Time; 94 void predfs(int x) 95 { 96 ll[x]=++Time; vvv[Time]=val[x]; 97 for (int i=first[x];i;i=edge[i].next) 98 { 99 Edge &e=edge[i]; 100 predfs(e.to); 101 } 102 rr[x]=Time; 103 } 104 void maketree() 105 { 106 for (int i=1;i<=size;i++) in(a[i].pre,i); 107 Time=0; predfs(0); 108 } 109 bool go(int &x,int &p,char c) 110 { 111 Node &b=a[x]; 112 if (p) {if (s[p]==c) p++; else return 0; if (p==b.pos+b.Max) p=0;} 113 else 114 { 115 bool flag=1; 116 for (int i=first[x];i;i=edge[i].next) 117 { 118 Edge &e=edge[i]; 119 if (s[a[e.to].pos+a[x].Max]==c) 120 { 121 p=a[e.to].pos+a[x].Max+1; x=e.to; 122 flag=0; break; 123 } 124 } 125 if (flag) return 0; 126 if (p==a[x].pos+a[x].Max) p=0; 127 } 128 return 1; 129 } 130 }sa; 131 132 int root[maxn]; 133 struct SMT 134 { 135 struct Node{int ls,rs,cnt;}a[maxn*20]; 136 int size,n; 137 void clear(int N) {n=N; size=0;} 138 void insert(int &x,int y,int L,int R,int v) 139 { 140 x=++size; a[x].cnt=a[y].cnt+1; 141 if (L==R) return; 142 int mid=(L+R)>>1; 143 if (v<=mid) a[x].rs=a[y].rs,insert(a[x].ls,a[y].ls,L,mid,v); 144 else a[x].ls=a[y].ls,insert(a[x].rs,a[y].rs,mid+1,R,v); 145 } 146 void insert(int &x,int y,int v) {if (v) insert(x,y,1,n,v); else x=y;} 147 int ql,qr; 148 int Query(int y,int x,int L,int R) 149 { 150 if (ql<=L && R<=qr) return a[y].cnt-a[x].cnt; 151 else 152 { 153 int mid=(L+R)>>1,ans=0; 154 if (ql<=mid) ans+=Query(a[y].ls,a[x].ls,L,mid); 155 if (qr>mid) ans+=Query(a[y].rs,a[x].rs,mid+1,R); 156 return ans; 157 } 158 } 159 int query(int y,int x,int L,int R) {ql=L; qr=R; return Query(y,x,1,n);} 160 }t; 161 162 void solve2() 163 { 164 for (int i=n;i;i--) sa.insert(getnum(s[i]),i); 165 sa.maketree(); 166 t.clear(n); 167 // for (int i=1;i<=sa.Time;i++) cout<<sa.vvv[i]<<' ';cout<<endl; 168 for (int i=1;i<=sa.Time;i++) t.insert(root[i],root[i-1],sa.vvv[i]); 169 int op,x,y,last=0; char c; 170 while (lq--) 171 { 172 op=qread(); 173 if (op==2) continue; 174 x=qread()^last; y=qread()^last; y++; 175 while (((c=getchar())<'a' || c>'z') && (c<'A' || c>'Z')); 176 int xx=0,pp=0; bool flag=1; 177 do 178 { 179 y--; 180 c=getch((getnum(c)+last)%52); 181 if (flag) flag=sa.go(xx,pp,c); 182 }while (((c=getchar())>='a' && c<='z') || (c>='A' && c<='Z')); 183 if (!flag) printf("%d\n",(last=0)); 184 else 185 { 186 int R=root[sa.rr[xx]],L=root[sa.ll[xx]-1]; 187 printf("%d\n",(last=t.query(R,L,x,y))); 188 } 189 } 190 } 191 192 int main() 193 { 194 scanf("%s",s+1); n=strlen(s+1); lq=qread(); 195 if (n<=5000 && lq<=5000) solve1(); 196 else solve2(); 197 return 0; 198 }
真实做法后缀平衡树,暂时不会。