[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;         }     } }
原创粉丝点击