[bzoj2555][后缀平衡树]SubString
来源:互联网 发布:手机怎么申请淘宝号码 编辑:程序博客网 时间:2024/05/21 22:38
2555: SubString
Time Limit: 30 Sec Memory Limit: 512 MB
Submit: 2857 Solved: 856
[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
2AQUERY BADD BBABBBBAAB
Sample Output
0
HINT
40 % 的数据字符串最终长度 <= 20000,询问次数<= 1000,询问总长度<= 10000
100 % 的数据字符串最终长度 <= 600000,询问次数<= 10000,询问总长度<= 3000000
新加数据一组–2015.05.20
Source
Ctsc模拟赛By 洁妹
ps:这篇题解是纪念我学的后缀平衡树,主要提了提后缀平衡树的用法。
sol:
题目的强制在线有坑点,mask只有在mask = mask xor Result时改变结果,其他时候都是局部变量。
这道题我当做后缀平衡树的裸题来做了。
下面阐述一下后缀平衡树
节点编号x存的是字符在字符串中的位置,这个x在树中的位置表示其后缀的大小,后缀平衡树只支持在前面插字符,这相当于是插入了一个后缀。如果题目要求在后面插,那么我们可以视作这个字符串的后缀为其前缀,做起来没差别。
我的后缀平衡树使用treap来达到重量平衡。使得保证树的形态的同时,使其为key(rand)值的小根堆。
后缀平衡树支持几个经典操作
1:插入字符(即某个后缀)
2:查询某个后缀(可以不包含在本串中)在树中的排名
3:查询排名为x的某个后缀
后缀平衡树的实质为动态的sa,因此sa支持的操作后缀平衡树都支持。
1:
朴素算法:插入字符时,要先和当前节点的后缀比较大小,一位一位的比较,直到某位不同时比出大小。这个显然太慢
优化算法:我们发现只需要比较第一位,之后的后缀在之前处理过。因此我们可以通过询问2个后缀的排名来比较,实现log^2的插入。
优越算法:我们对后缀平衡树中的每个节点进行规定,设其区间为(l,r),则这个节点的值为mid,左儿子的区间为(l,mid),右儿子为(mid+1,r),值直接代表该后缀在后缀平衡树中的相对大小。则我们在插入字符时可以O(1)的比较后缀。
我们应该怎么实现这个标号法呢?由于重量平衡的性质,每个点的子树大小期望为O(1),因此我们在每次旋转操作的时候,可以直接暴力修改整个子树的标号值。因为重量平衡的性质,所以树高为log级别,标号每次都/2,所以我们开long long就能够把区间存下来了。
2:
查询某个后缀的排名,就是带着一个串在后缀平衡树上走。
朴素算法:和当前节点一位一位比较
优化算法(假的):二分,用字符串哈希求LCP比较。
需要注意的是,朴素算法一般比优化算法快。
3:
从这个节点往上走记录size即可。
正文:
本题要求在字符串后面插入字符,那就把前缀看成后缀即可。
求字符串x在文本串中出现了几次,实际上就是求
小于x#的后缀的数目 - 小于x的后缀的数目(#为最大字符)
本题前缀是后缀,就是把#放前面
#include<cstdio> #include<algorithm> #include<string> #include<cstring> #include<cstdlib> #include<cmath> #include<iostream> #define ll long longusing namespace std; const int N=600005; int n,m,rt,tot; ll rank[N]; struct tree{int son[2],key;}a[N];int key[N];char sr[N]; inline int read() { char c; bool flag=false; while((c=getchar())>'9'||c<'0') if(c=='-')flag=true; int res=c-'0'; while((c=getchar())>='0'&&c<='9') res=(res<<3)+(res<<1)+c-'0'; return flag?-res:res; } int size[N]; inline void updata(int x,ll l,ll r) { if(!x) return; size[x]=1; rank[x]=l+r>>1; updata(a[x].son[0],l,rank[x]); updata(a[x].son[1],rank[x]+1,r); size[x]=size[a[x].son[0]]+size[a[x].son[1]]+1; } inline bool cmp(int x,int y) { return sr[x]<sr[y]||sr[x]==sr[y]&&rank[x-1]<rank[y-1]; } inline void rotate(int x,int y,ll l,ll r) { int Side=a[y].son[1]==x; a[y].son[Side]=a[x].son[Side^1]; a[x].son[Side^1]=y; updata(x,l,r); } inline void insert(int &x,ll l,ll r) { ll mid=l+r>>1; if(!x) { x=++tot; size[x]=1; a[x].key=rand(); rank[x]=mid; return; } size[x]++; if(cmp(tot+1,x)) insert(a[x].son[0],l,mid); else insert(a[x].son[1],mid+1,r); if(a[tot].key<a[x].key) { rotate(tot,x,l,r); x=tot; } } int l,len,mask,lastAns=0; char s[N],Sr[N]; inline void get_ready(int mask) { scanf("%s",s); l=strlen(s); for(int i=0;i<l;++i) { mask=(mask*131+i)%l; swap(s[i],s[mask]); } } int P=2333;inline void lcp(int x,int &LCP){ int e=min(l+1,x); for(int i=1;i<=e;++i) if(sr[x-i+1]==s[l-i+1]) LCP++; else break;}inline int cmp_(int x)//1表示x比较小 0表示大 2= { if(sr[x]!=s[l]) return sr[x]<s[l]; int LCP=0; lcp(x,LCP); if(LCP==l+1&&LCP==x) return 2; if(LCP==l+1) return 0; if(LCP==x) return 1; return sr[x-LCP]<s[l-LCP];}inline int get_rank(int x) { if(!x) return 0; int flag=cmp_(x); if(flag==1) return size[a[x].son[0]]+1+get_rank(a[x].son[1]); else if(flag==0) return get_rank(a[x].son[0]); else if(flag==2) return size[a[x].son[0]];} int main() { // freopen("SubString.in","r",stdin); // freopen("SubString.out","w",stdout); srand(19260817); m=read(); scanf("%s",sr+1); len=strlen(sr+1); for(int i=1;i<=len;++i) insert(rt,1,(ll)1<<62); while(m--) { scanf("%s",Sr+1); get_ready(mask); if(Sr[1]=='A') for(int j=0;j<l;++j) { sr[++len]=s[j]; insert(rt,1,(ll)1<<62); } if(Sr[1]=='Q') { if(l>len) { lastAns=0; printf("%d\n",lastAns); mask^=lastAns; continue; } --l; lastAns=-get_rank(rt); for(int j=l;j>=0;--j) s[j+1]=s[j]; s[0]=(char)127; ++l; lastAns+=get_rank(rt); printf("%d\n",lastAns); mask^=lastAns; } } }
- [bzoj2555][后缀平衡树]SubString
- bzoj2555: SubString(后缀自动机+动态树)
- 【BZOJ2555】SubString 后缀自动机 暴力
- 【bzoj2555】SubString LCT+后缀自动机
- BZOJ2555:SubString 后缀自动机 LCT
- [BZOJ2555][LCT][后缀自动机]SubString
- 【bzoj2555】SubString 后缀自动机+LCT
- 后缀自动机 + LCT 【bzoj2555】SubString
- BZOJ2555 SubString 后缀自动机+LCT
- [BZOJ2555]SubString(后缀自动机+lct)
- 【BZOJ2555】SubString
- [bzoj2555]SubString
- [bzoj2555]SubString
- 【bzoj2555】SubString
- BZOJ2555: SubString
- bzoj2555: SubString
- bzoj2555 SubString
- [BZOJ2555]SubString
- Android之多线程解析(二)之Runnable、Callable、FutureTask
- python之路——字符串操作
- LibSVM
- 禁用COOKIE后SESSION是如何传递
- 分治法排序
- [bzoj2555][后缀平衡树]SubString
- py thon 多线程(转一篇好文章)
- Codeforces Round #423 A. Restaurant Tables
- FutureTask源码浅析
- 技能树
- ios流类库体系及格式控制
- Tomcat 8 404
- Linux网络配置(简单)
- sscanf函数和正则表达式